c++ - 从编译器获取参数时,有没有办法避免预处理器宏?

标签 c++ gcc macros preprocessor compile-time-constant

我正在编写一个需要进行一些编译时间计算的库,并构建一个编译时间常量数组。问题是我需要一种方法来指定这个数组的最大大小......我知道的唯一方法是让它成为传递给编译器的可配置选项。

然后您可以将它与预处理器指令一起使用,例如:

#ifndef MAX_SIZE
    constexpr auto maxSize = 42; // Some default value if no MAX_SIZE is specified
#else
    constexpr auto maxSize = MAX_SIZE;
#endif

要在使用 gcc 编译时设置最大大小,可以使用选项 -DMAX_SIZE=<desired_size> 编译代码.

我遇到的问题是它涉及使用预处理器宏来获取 MAX_SIZE来自编译器的参数。预处理器宏被认为是邪恶的原因有很多(我不会在这里讨论,因为这不是问题的重点)。

有什么方法可以在不使用预处理器宏的情况下实现此功能? (我有多达 C++20 可用,因此请随意使用您的解决方案——嗯,大多数情况下,其中一些尚未由 gcc 10 实现)

最佳答案

还有其他方法,但您可能不想使用它们。您正在做的是很好地使用预处理器。虽然我会写类似的东西:

#ifndef MAX_SIZE
#define MAX_SIZE 42
#endif
constexpr size_t maxSize = MAX_SIZE;

这样,实际的代码部分、变量类型、名称等只需要编写一次。还要考虑:
#indef MAX_SIZE
#error "You need to define MAX_SIZE to compile this code, e.g. -DMAX_SIZE=42"
#endif

这样,当他们不想使用默认值时,有人不会使用默认值,因为他们不知道定义它,或者构建系统中的某些东西使 -D 标志在某处丢失。

但是还有其他方法可以避免使用预处理器宏!

生成源代码本身。虽然这可能看起来很复杂,而且通常很复杂,但有一些方法可以让它变得不那么复杂。构造代码,使必须生成的部分很小。例如,从 maxSize 的单个定义中导出其他值而不是生成所有需要知道大小的代码。在某些情况下,也有一些系统已经可以做到这一点。例如,如果使用 CMake,请创建一个 header.h.in 文件,如下所示:
constexpr size_t maxSize = @MAXSIZE@;

然后将其放入 CMakeLists.txt 文件中:
set(MAXSIZE 42)
configure_file(header.h.in header.h @ONLY ESCAPE_QUOTES)

项目建成后,cmake会将header.h.in转成header.h,@MAXSIZE@改为42。
这没有使用 C++ 预处理器,但我们有效地使用了 CMake 预处理器在编译文件之前对其进行预处理,所以真的,有什么不同吗?它只是一种不同的预处理器语言(它不如 C/C++ 预处理器语言好)。

另一种方法是使用链接时间常数。链接器符号通常是函数或全局变量的名称。具有静态存储持续时间的东西。符号的值是对象的地址。但是可以在链接器的命令中定义您想要的任何符号。这是一个示例 C 文件:
#include <stdio.h>
char array1[1];
extern array2[];
int main(void) { printf("%p %p\n", array1, array2); return 0; }

使用 gcc 编译为 gcc example.c -Wl,--defsym=array2=0xf00d .

就像它打印array1的地址一样,它会打印0xf00d作为array2的地址.因此,我们在代码中注入(inject)了一个常量,而不使用任何预处理器,无论是 C 还是 CMake。

但是编译器不知道这个值,只有链接器知道。它不是“整数常量表达式”,不能在某些地方使用,例如大小写标签或具有静态存储持续时间的对象的大小。因为编译器需要知道那些编译代码的确切值。编译器在不知道 array1 的确切值的情况下生成了 printf 调用的代码。或 array2 .对于 case 语句标签,它无法做到这一点。这实际上是在 C/C++ 标准中存在“整数常量表达式”时,并且与常量和具有整数类型的表达式不同。

关于c++ - 从编译器获取参数时,有没有办法避免预处理器宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60217410/

相关文章:

c++ - __func__ 未在预处理输出中替换

c++ - GCC 如何处理宏中的引号?

c++ - MSVC多行宏编译器错误

c++ - 尽管 dllExport 正确,但没有函数导出到 DLL - Visual Studio

c++ - 哪个版本的 GCC 引入了对原子内置函数的支持?

c++ - 如何在 C++ 中使用循环

c - 升级到Mojave后,无法在Mac上编译C程序

gcc - "#pragma pack"和 "__attribute__((aligned))"有什么区别

c++ - 代码块的 Boost 库设置

c++ - 如何将 C++ 子例程链接到 x86 汇编程序?