C++,用define声明一个数组;怎么了? (简单快捷)

C++, declaring an array with define; What is happening? (Easy and quick)


我正在尝试学习一些 C++,但我遇到了这段代码:

static const unsigned char t_CountBits13[8192] = {
    #define B2(n) n,     n+1,     n+1,     n+2
    #define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
    #define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
    #define B8(n) B6(n), B6(n+1), B6(n+1), B6(n+2)
    #define B10(n) B8(n), B8(n+1), B8(n+1), B8(n+2)
    #define B12(n) B10(n), B10(n+1), B10(n+1), B10(n+2)
    B12(0), B12(1)
};

我觉得这很奇怪!
问题 1:这是否与:

相同
#define B2(n) n,     n+1,     n+1,     n+2
#define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
#define B8(n) B6(n), B6(n+1), B6(n+1), B6(n+2)
#define B10(n) B8(n), B8(n+1), B8(n+1), B8(n+2)
#define B12(n) B10(n), B10(n+1), B10(n+1), B10(n+2)

static const unsigned char t_CountBits13[8192] = {B12(0), B12(1)};

问题二:

#define B2(n) n,     n+1,     n+1,     n+2

我认为 C++ 函数只能 return 一个值是否正确?因为看起来你在这里定义了一个 return 的函数(例如 lua)

亲切的问候!

答案1:数组将被初始化为相同的值。预处理后的结果和白色有点不同space,所以从文字上看是不一样的,但是编译的结果应该是一样的。

答案2:如评论中所述,这些不是C++函数,而是C预处理器解释的宏。这些导致在编译器解释它之前进行文本扩展。您示例中的扩展太大,无法在此处显示(2 * 4^6 = 8192 个元素很多)。我将减少它作为一个例子。

原始源代码:

static const unsigned char data[] = {
#define B2(n) n, n+1
#define B4(n) B2(n), B2(n+1)
    B4(1), B4(2)
};

预处理器的输出(例如,gcc -E tst.c:

的输出
# 1 "tst.c"
# 1 "<command-line"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line" 2
# 1 "tst.c"
static const unsigned char data[] = {


    1, 1 +1, 1 +1, 1 +1 +1, 2, 2 +1, 2 +1, 2 +1 +1
};

注意预处理指令所在的空白行。另请注意,这些值不是算术结果,而是文本扩展。这是编译器将实际解释的代码。另请注意,扩展是通过上面定义的 #define 宏递归的。

# 开头的行是预处理器的附加信息,包括命令行定义和文件信息等内容。它在这个例子中相当平淡,但是如果你有一个 #include <somefile.h> 你会看到它的内容,它包含的文件的内容(递归),以及一些 # 行指示这些位置的实际行号(通常由编译器用于显示警告和错误消息,因为当它得到它时,曾经是第 5 行的行现在可能是第 2592 行,但您希望警告指示第 5 行)。

查看预处理器的输出对调试奇怪的错误很有帮助。当来自编译器的消息没有意义时,它可能是一个错误的 #define 替换了您没有预料到的文本。例如,您可能有以下代码

int limit(int x) {
    if (x > LIMIT) {
        return LIMIT;
    }
    return x;
}

编译器可能会在 int limit(int x) {

行说 error: expected identifier or '(' before numeric constant

如果您查看预处理的输出,您可能会发现

int 5(int x) {

并意识到以下行已进入您的代码(原始源文件或包含文件)

#define limit 5

请注意 limit 是小写的,我们尝试将函数命名为小写,但预处理器将其替换为 5。#define 可能应该是 LIMIT(全部大写)

这个回答有点长,但我希望能说明 #define 的文本替换性质,并提供一些有关查找您自己的代码的中间表示的提示。

注意:预处理器的实际输出取决于您的工具链。以上信息适用于 GNU 编译器集合。一些工具链实际上并没有将预处理器阶段与编译阶段分开,而是简单地表现得好像它们分开了,这是语言允许的。