这是一个问题:
Q1. C预处理器能进行算术运算吗?
这是另一个问题:
Q2. C预处理器能计算算术表达式,然后将结果“粘贴”到我的代码中,而不是将原始表达式“粘贴”到代码中吗?
Q1的答案是是。Q2的答案是否定的。这两个事实可以用下面的文件说明:
foo.c
#define EXPR ((1 + 2) * 3)
#if EXPR == 9
int nine = EXPR;
#else
int not_nine = EXPR;
#endif
如果我们将这个文件传递给C预处理器,可以通过cpp foo.c
或等效的gcc -E foo.c
来实现,我们会看到以下输出:
int nine = ((1 + 2) * 3);
预处理器保留定义变量 int nine
的那一行,删除定义变量 not_nine
的那一行,这表明它正确执行了计算表达式 #if EXPR == 9
所需的算术运算。
定义的预处理文本为 int nine = ((1 + 2) * 3);
,这表明 #define
指令使预处理器将 EXPR
替换为其定义 ((1 + 2) * 3)
,而不是其定义的算术值 9
。
C预处理器除了 #define
指令外,还有没有其他指令会产生第二种效果呢?答案是否定的。
但这当然并不意味着定义变量 int nine
必须涉及 运行时计算,因为编译器几乎肯定会在编译时计算算术表达式 ((1 + 2) * 3)
并将其替换为常量 9
。
我们可以通过检查编译后的目标文件来看编译器如何翻译源文件。大多数工具链都会提供类似 GNU binutils 的 objdump
工具来协助完成这项工作。如果我使用 gcc 编译 foo.c
:
gcc -c -o foo.o foo.c
然后调用:
objdump -s foo.o
要查看 foo.o
的全部内容,我得到:
foo.o: file format elf64-x86-64
Contents of section .data:
0000 09000000 ....
Contents of section .comment:
0000 00474343 3a202855 62756e74 752f4c69 .GCC: (Ubuntu/Li
0010 6e61726f 20342e38 2e312d31 30756275 naro 4.8.1-10ubu
0020 6e747539 2920342e 382e3100 ntu9) 4.8.1.
希望在 .data
部分中硬编码的数字 9
已经出现了。
请注意,预处理器的算术能力仅限于整数算术。
gcc
版本,而是一个完全不同的东西。我认为,一般情况下也很少见到支持这个编译器的库。祝你好运。也许由于这个编译器并不那么流行,你应该尝试从一些针对 IAR 的 IRC、邮件列表或论坛获得帮助。 - user2485710