关于转换为整数常量表达式(在标准C中)
在标准C(我的意思是C99或C11)中,我们有所谓的整数常量表达式 ,它们是常量表达式,其操作数都是常量整数。 还有其他约束,以避免表达式中的逗号运算符。
但是,在某些特殊情况下,允许使用其他非整数对象(甚至是非常量对象)。
例如,如果将sizeof
运算符应用于大小在转换时间中已知的对象,则允许将其作为整数常量表达式的一部分 (请注意, sizeof
始终返回整数值)。
此外,有时也允许显式转换为整数类型。
标准C99建立以下规则:
标准C99,第6.6节(第6节):
整数常量表达式)应具有整数类型,并且只能具有整数常量,操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,以及作为强制转换的直接操作数的浮点常量。
标准C99
我的问题是: “浮动常数是演员的直接操作数”的确切含义是什么?
浮点常量类似于3.14e + 3,或者是0x2.11p-5。
也就是说,不是float类型的一般常量表达式,而只是浮点文字。
然后,我明白在上面的定义中只允许这样的事情:
(int) 3.14
但是不允许涉及浮动文字的操作 。
这排除了以下情况:
(int) -3.14 /* The minus sign is not part of the constant: it is an operator */ (int) (3.14) /* The parenthesis are an operator acting on the literal 3.14 */
最后一种情况不需要在转换时间内执行任何浮点算术运算,并且相当于没有括号: (int) 3.14
。
但是,它不是演员的直接操作数 。
那么,我们是否必须考虑(int) (3.14)
是否是[有效整数常量表达式的一部分](根据定义)?
另一方面,编译器GCC(带选项:-std = c99 -pedantic-errors)给出了(int) (3.14)
是一个有效的整型常量表达式 ,例如在声明中如下所示:
#define BITW (int) (3.14) struct { unsigned bitfield: BITW } test; // Translation success
(但是,通过执行#define BITW (int) (+3.14)
它无法按预期转换)。
虽然措辞选择不当可能意味着(int) (3.14)
不符合整数常量表达式,但我认为这只是措辞中的一个错误。 有一个类似的问题,可以说是NULL
规范的错误:允许任何空指针常量,其中空指针常量定义为:
- 一个整数常量表达式,其值为0或
- 这样的表达变为
void *
。
但是,要作为NULL
的定义有用,表达式应该正确括号; 我所知道的所有现有实现都是这样做的。 但是通过严格的读取,while (void *)0
是一个空指针常量, ((void *)0)
不是(它是括号运算符应用于空指针常量)。
理想情况下,应在规范中的某处添加语言,以澄清括号不会影响这样的事情。
有关信息,gcc维护者和开发人员Joseph Myers在其个人页面上讨论了C99标准中常量表达式的问题。 原始文本10年前出现在comp.std.c上,但后来扩展了。
http://www.polyomino.org.uk/computer/c/const-exprs-issues.txt
在他提出的常数表达问题中,你所描述的问题在他的观点(5)中进行了讨论:
(5)常量表达式的“操作数”(6.6段6和8)是什么? 据推测,它在某种意义上意味着“终极”操作数,将各种运算符递归到它们的操作数,但这没有指定。 假设复合文字(例如(const int){0})并不意味着是常量表达式(对匿名变量的引用),但从文本中很难清楚0在这里不是操作数。 当复合文字出现在sizeof表达式中,其结果不是表达式未评估部分中的整数常量时,表达式是否为算术常量表达式可能取决于复合文字中存在哪些强制转换。 此外,人们可以预期括号是纯语法而不是“操作数”,因此(int)(0.0)是一个整数常量表达式,就像(int)0.0是,而((void *)0)是一个空指针常量,但这没有说明。
在他的个人页面中提到了这个文本,它被写成:
我还讨论了常量表达式的问题(不是上面的前DRforms;部分可能在实现经验后成为DR)。
据我所知,第(5)点提出的术语问题在DR中没有进一步提出。