【问题标题】:IS_BIG_ENDIAN macro works but not in #ifIS_BIG_ENDIAN 宏有效,但在 #if 中无效
【发布时间】:2021-07-14 08:52:38
【问题描述】:

这让我很困惑: 如果我注释掉从#if 到#endif 的所有内容,程序将在C99​​ (TinyCC) 中编译。有了条件,它会在 #if 子句之前的行给出预期的错误 ')' (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); 
}

【问题讨论】:

  • This is puzzling me: 这是预期行为,一切正常且正确。为什么令人费解?
  • 没想到...

标签: c c-preprocessor


【解决方案1】:

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

如果注释掉与#if 一致的行,则不会评估宏。这就是您不会收到错误消息的原因。

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

【讨论】:

  • 但是如果我把#if...#endif 注释掉,宏在主函数中被正确评估...
  • 当然,因为编译器可以评估它。请注意,预处理器和编译器是两种不同的野兽,使用不同的语言。
  • “预处理器通常不知道如何评估 C 表达式”→“预处理器通常不知道如何评估所有 C 表达式。”当然,预处理器可以根据 C 2018 6.10.1 4 中的规则评估 #if 指令中的 constant-expression
【解决方案2】:

#if#elif 指令对常量表达式进行操作。特别是,常量表达式不能使用任何对象的值或地址(lvalue)。

理论上,C 程序按翻译阶段 1 到 8 的顺序进行翻译。预处理指令在翻译阶段 4 执行,但直到翻译阶段 7 才形成对象。有关翻译的更多信息,请参阅“Phases of translation”阶段。

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


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

【讨论】:

  • @EricPostpischil 谢谢,我已经更正了。我在想在第 6 阶段之后必须有一些“连接字符串文字”的内部表示,但我想这可以通过用单个连接字符串文字标记替换一系列字符串文字标记来完成。
【解决方案3】:

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

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

【讨论】:

  • 你被否决了(不是我),因为那个人可能认为这不是一个答案。这是正确的,您可以编辑您的问题以添加此内容以供以后参考。而且我认为,它本身是有帮助的,但仍然不是答案。不幸的是,没有发表评论为什么它被否决。
  • 多字符常量中的字节顺序不必与其他对象中的字节顺序或存储单元中位域的顺序相同。多字符常量的值甚至不必是其字符值的串联;它的值是实现定义的。此外,这个答案不必要地依赖于 ASCII。 (例如,'\x1\x2' 可以用来避免对字符集的依赖。)
猜你喜欢
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多