【问题标题】:sizeof() is not executed by preprocessor预处理器不执行 sizeof()
【发布时间】:2011-05-21 12:49:37
【问题描述】:
#if sizeof(int) != 4
/* do something */

在#if 中使用 sizeof 不起作用,而在 #define 中使用它,为什么?

#define size(x) sizeof(x)/sizeof(x[0]) /*works*/

【问题讨论】:

  • 为此使用 (u)intptr_t 之类的东西。
  • sizeof(int) 在预处理器中变成0(0),我相信。
  • 无论如何,使用预处理器对int 的大小进行代码测试肯定会非常错误。如果需要 32 位整数,请使用 int32_t。如果您需要一个可以保存至少 32 位值的整数类型,请使用 int_least32_t 或 long。在任何情况下您都不需要测试 sizeof(int); sizeof(int) 的唯一合法用途是确定要分配的内存量(例如,将其传递给 calloc)。
  • 我会在sizeof(x)/sizeof(x[0])周围加上括号。
  • 你可能想要的是assert(sizeof(int) == 4)

标签: c c-preprocessor


【解决方案1】:

没有什么是邪恶的 - 一切都可能被滥用,或者在你的情况下被误解。 sizeof 运算符是编译器功能,但编译器功能对预处理器不可用(在编译器参与之前运行),因此不能在#if 预处理器指令中使用。

但是,当你说:

#define size(x) sizeof(x)/sizeof(x[0])

并使用它:

size(a)

预处理器执行一个交给编译器的文本替换:

sizeof(a)/sizeof(a[0])

【讨论】:

  • +1,代表Nothing is evil。我厌倦了听到“宏观是邪恶的”。人们用它称他们为邪恶。 :)
  • +1。我认为它很好地解释了这个问题。如果你能详细说明#if 会更好。
  • @iammilind 是的,我在自己的代码中使用了相当多的宏,一方面用于另一方面,但通常用于实现抛出或记录。它从来没有引起任何问题。
  • “x 是邪恶的”这件事是故意夸张的。并不是说任何语言功能实际上都是一个坏主意并且应该永远被使用(如果是这样的话,任何理智的语言都会弃用和/或删除所述功能),但更多的是它经常有不那么明显的陷阱,可能应该仅限于最适合的情况(和/或应该知道并考虑陷阱)。
  • 在预处理器表达式中准确解释 sizeof 或 Easter_bunny 等标识符会发生什么可能会有所帮助。如果它们本身不是宏,它们会变成零,正如我已经解释的那样。
【解决方案2】:

C“预处理器”宏只计算常量和其他宏

简短的回答是预处理器表达式仅提供对由其他预处理器宏和常量组成的表达式的有意义的评估。

试试这个,你将不会得到错误:

#if sizeof < 2
int f(int x) { return x; }
#endif

如果你生成程序集,你会发现sizeof &lt; 2 编译了函数而sizeof &gt;= 2 没有。两者都不返回错误。

发生了什么事?事实证明,除了预处理器宏本身之外,预处理器(“宏”)表达式中的所有标识符都被替换为 0。所以上面的#if 和说的一样:

#if Easter_Bunny < 2

或

#if 0 < 2

这就是为什么在预处理器表达式中错误地使用 sizeof 运算符时实际上不会出现任何错误的原因。

碰巧,sizeof 是一个运算符,但它也是一个标识符,并且本身不是宏的标识符在预处理器表达式中都变成了0。至少在概念上,预处理器在编译器之前运行。它可以将非 C 语法转换为 C,因此在它运行时,C 程序甚至还没有被解析。目前还不能引用实际的 C 对象:它们不存在。

很自然,定义的替换文本中的sizeof 会简单地传递给编译器,就像使用宏的替换文本一样。

【讨论】:

    【解决方案3】:

    预处理器无法评估sizeof 运算符的结果。这是编译器在预处理器完成很久之后才计算出来的。

    由于第二个表达式导致编译时计算,因此它可以工作。第一个是对预处理器的不可能测试。

    【讨论】:

      【解决方案4】:

      #define 只是文本替换。 #if 作为条件预处理器指令评估 sizeof() 但在预处理时预处理器不知道 sizeof() 是什么。预处理器在词法分析阶段之前运行。

      【讨论】:

        【解决方案5】:

        sizeof 在编译时被替换。 预处理在编译开始之前运行。

        【讨论】:

          【解决方案6】:

          编译器不会触及任何一行。相反,预处理器会翻阅文件,用您的宏替换任何 size(x) 实例。编译器确实看到了这些替换。

          【讨论】:

            【解决方案7】:

            预处理器不知道sizeof 运算符,它只是无法理解它。所以#if 不起作用,因为它必须理解它才能工作,因为它是一个条件条件预处理器;它需要知道它的评估结果是真还是假。

            但是#define 不需要理解sizeof,因为#define 只是用于文本替换。预处理器在源代码中搜索size 宏(在#define 中定义),并将其替换为定义的内容,在您的情况下为sizeof(x)/sizeof(x[0])。

            【讨论】:

              【解决方案8】:

              它不起作用的原因是,在代码到达编译器之前,预处理器宏在一次传递中被“评估”。因此,在 if 预处理器指令中,无法计算 sizeof(int)(实际上是 sizeof(int) != 4),因为这是由编译器完成的,而不是预处理器。

              但是,define 语句只是进行文本替换,所以当涉及到编译器时,在任何你有 'size(x)' 的地方你都会有 'sizeof(x)/sizeof(x[0])' ,然后在编译阶段进行评估......在代码中你有'size(x)'的每个点

              【讨论】:

                【解决方案9】:

                如果您想检查处理器中整数的大小,请使用您的 make 系统在运行预处理器之前发现系统上的整数大小,并将其写入头文件,例如#define SIZEOF_INT 4,包含这个头文件并做#if SIZEOF_INT == 4

                例如,如果您使用 cmake,则可以使用 CMAKE_SIZEOF_INT 变量,该变量具有可以放入宏中的整数大小。

                【讨论】:

                  猜你喜欢
                  • 2011-05-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-05-12
                  • 2010-12-06
                  • 1970-01-01
                  相关资源
                  最近更新 更多