首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在C99中具有可能溢出的常量表达式的初始化器

在C99中具有可能溢出的常量表达式的初始化器
EN

Stack Overflow用户
提问于 2015-04-15 13:59:51
回答 3查看 778关注 0票数 6

这是有效的C99代码吗?如果是的话,它是否定义了实现定义的行为?

代码语言:javascript
运行
复制
int a;
unsigned long b[] = {(unsigned long)&a+1};

根据我对C99标准的理解,根据ISO C99标准第6.6节,这可能是有效的:

  1. 整数常量表达式应具有整数类型,并且只能具有整数常量(.)的操作数。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,但作为操作数的一部分,则应转换为相当大的运算符。
  2. 对于初始化器中的常量表达式,允许有更大的空间。这种常量的表述应是或评估以下之一:
代码语言:javascript
运行
复制
- 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时,即使用以下代码:

代码语言:javascript
运行
复制
int a;
unsigned long b[] = {(unsigned int)&a+1};

然后,两个编译器都抱怨表达式不是编译时常量。

EN

Stack Overflow用户

发布于 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版本中有一个编译错误。

票数 1
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29652323

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档