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 编译器集合。一些工具链实际上并没有将预处理器阶段与编译阶段分开,而是简单地表现得好像它们分开了,这是语言允许的。
我正在尝试学习一些 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 编译器集合。一些工具链实际上并没有将预处理器阶段与编译阶段分开,而是简单地表现得好像它们分开了,这是语言允许的。