IS_BIG_ENDIAN 宏有效但在 #if 中无效

IS_BIG_ENDIAN macro works but not in #if

这让我很困惑: 如果我注释掉从#if 到#endif 的所有内容,程序将在 C99 (TinyCC) 中编译。其中的条件在#if 子句

之前的行给出错误 ')' expected (got "0")
#include <stdio.h>

#define IS_BIG_ENDIAN (!*(unsigned char *)&(uint16_t){1})

#if IS_BIG_ENDIAN 
   struct ieee {     
     unsigned long sign:1;
     unsigned long expo:8;
     unsigned long mantissa:23;
    };   
   
#else
 
  struct ieee {   
    unsigned long mantissa:23;  
    unsigned long expo:8;
    unsigned long sign:1;
  };    

#endif


int main()
{  
 printf ("%d\n",IS_BIG_ENDIAN); 
}

预处理器通常不知道如何计算所有 C 表达式。它的功能非常有限。

如果注释掉 if line with #if,宏将不会被计算。这就是为什么您不会收到错误的原因。

但是,如果对宏求值,则让预处理器解析表达式。显然它不能这样做。

#if#elif 指令对常量表达式进行操作。特别是,常量表达式不能使用任何 object (lvalue).

的值或地址

理论上,C 程序按翻译阶段 1 到 8 的顺序进行翻译。预处理指令在翻译阶段 4 执行,但在翻译阶段 7 之前不会形成 objects。参见“Phases of translation" 了解更多关于翻译阶段的信息。

没有标准的方法来提供字节顺序作为预处理器的常量表达式,但一些实现通过预定义的宏或系统中定义的宏提供此信息 header。


还应注意,基本 object 的字节顺序和连续位域成员的打包方向(即打包是从存储单元的最高有效端还是最低有效端开始)不是彼此相关,即 big-endianness 并不意味着位域成员打包从最重要的一端开始,反之亦然。至于字节序,实现可以通过预定义的宏或系统中定义的宏提供有关位域成员打包顺序的信息header。

为了完整起见,我找到了预处理器可以管理的测试:

      #define LITTLE_ENDIAN 0x41424344UL 
      #define BIG_ENDIAN    0x44434241UL
      #define PDP_ENDIAN    0x42414443UL
      #define ENDIAN_ORDER  ('ABCD') 
    
   #if ENDIAN_ORDER==BIG_ENDIAN