我想打印 typeof() 输出的类型,但 typeid 仅在 C++ 中可用。为什么我不能使用字符串化来获取该类型的名称?
#define GET_STRING(s) #s
#define example(input) \
do { \
char test[20] = GET_STRING(typeof(input)); \
printf(test); \
} \
while (0) \
这将打印出“typeof()”,其中输入字符串化。为什么预处理器在处理 typeof() 之前进行字符串化?有没有办法克服这种行为?
如果像 GET_STRING(int) 那样传递类型,则可以直接对类型进行字符串化,因此使用 typeof() 应该具有相同的行为。
为什么预处理器在检查 typeof() 之前要进行字符串化?
“preprocessor”中有这个“pre”前缀,意思是“之前”。预处理器在大多数其他事情之前工作。 这里是翻译阶段的有序列表。注意 #4 下的“执行预处理指令,扩展宏调用”,以及 #7 下的“每个预处理标记都转换为一个标记。生成的标记在语法和语义上进行分析并翻译为翻译单元” .
有办法克服这种行为吗?
没有。
如果像 GET_STRING(int) 那样传递类型,则可以直接对类型进行字符串化,因此使用 typeof() 应该具有相同的行为。
编译器的行为由语言标准控制,而不是由用户模糊的愿望控制。在断言编译器应该做什么或不应该做什么之前,您应该引用该标准。如果你不喜欢标准的内容,你可以写一个提案来修改它并等待它被接受(但我不会屏住呼吸)。
这里是标准关于字符串化的说法:
[...] 字符串化参数中每个预处理标记的原始拼写保留在字符串文字中 [...]
程序中
typeof
标记的原始拼写是“typeof”,因此这就是字符串文字中的内容。
你不能这样做的主要原因是因为编译器编写者很懒并且专注于利用未定义的行为来达到优化目的*,从而剥夺了他们实际实现有用功能的能力,例如允许程序员在编译时访问类型。 (这没有任何借口,因为他们实际上do一直在对该语言实现有用的扩展。)
编译器确切地知道哪些类型是哪些类型,但设计者选择隐藏此信息,除非全能的“标准”强制他们这样做。
在这种特殊情况下,预处理器(也是由编译器人员编写的)不知道类型,因为它是与 C 不同的语言。分割语言有利有弊,这是弊端之一。 尽管如此,所需要的只是第二个处理步骤来利用类型,这就是我在编译时使用代码获取类型信息的方法。 这确实归结为懒惰......
任何对批评“标准”之神的诚实评估倾向于发脾气的人:Clang 和 gcc 总是添加扩展,这使得程序员的工作变得更容易,无论标准如何。 他们绝对没有理由不能拥有更好的类型信息作为 __builtin
。 事实上,编译器扩展有时最终会成为标准,因为它们非常有用。