这是有效的C99代码吗?如果是的话,它是否定义了实现定义的行为?
int a;
unsigned long b[] = {(unsigned long)&a+1};根据我对C99标准的理解,根据ISO C99标准第6.6节,这可能是有效的:
- an arithmetic constant expression,
- (...)
- an address constant for an object type plus or minus an integer constant expression.
但是,由于存在加法溢出的可能性,这可能不是一个常量表达式,因此不能使用有效的C99代码。
有人能确认一下我的推理是否正确吗?
请注意,GCC和Clang都不带警告地接受此代码,即使在使用-std=c99 -pedantic时也是如此。但是,当转换为unsigned int而不是unsigned long时,即使用以下代码:
int a;
unsigned long b[] = {(unsigned int)&a+1};然后,两个编译器都抱怨表达式不是编译时常量。
发布于 2015-04-15 14:23:31
首先,初始化器不一定是一个常量表达式。如果a有本地作用域,那么当它被推到堆栈上时,会在运行时为它分配一个地址。C11 6.6/7说,要使指针成为常量表达式,它必须是地址常量,在6.6/9中定义为:
地址常量是空指针,是指向指定静态存储期限对象的值的指针,或者是指向函数指示符的指针;它应该使用一元运算符或整数常量转换为指针类型显式创建,或者通过使用数组或函数类型的表达式隐式创建。
(强调地雷)
至于您的代码是否是标准C,是的。指针转换到整数是允许的,尽管它们可能伴随着各种形式的错误指定的行为。6.5/6中具体说明:
任何指针类型都可以转换为整数类型。除前面指定的结果外,结果是实现定义的。如果结果不能用整数类型表示,则行为未定义。结果不需要在任何整数类型的值范围内。
要安全地确保指针符合整数,您需要使用uintptr_t。但是我不认为指向整数转换的指针是你发布这个问题的原因。
关于整数溢出是否会阻止它成为编译时间常量,我不知道您是从哪里得到这种想法的。我不相信您的推理是正确的,例如,(INT_MAX + INT_MAX)是一个编译时间常数,而且它也保证会溢出。(GCC给你一个警告。)如果它溢出,它将调用未定义的行为。
至于为什么会出现关于表达式不是编译时常量的错误,我不知道。我不能在gcc 4.9.1上复制它。我尝试声明具有静态和自动存储时间的a,但没有区别。
听起来像是您意外地编译为C90,在这种情况下gcc会告诉您“错误:初始化器元素在加载时是不可计算的”。或者可能是我的gcc版本中有一个编译错误。
https://stackoverflow.com/questions/29652323
复制相似问题