在C中,在声明它的同一语句中使用变量是否有效?
在gcc 4.9和clang 3.5中,以下程序编译并运行且没有错误:
#include "stdio.h"
int main() {
int x = x;
printf("%d\n", x);
}
在gcc中输出0
和clang 32767
(最大的正2字节整数值)。
为什么这不会导致编译错误?这在任何特定的C规范中都有效吗?它的行为是否明确未定义?
答案 0 :(得分:4)
int x = x;
这是"有效"从某种意义上说它不违反约束或语法规则,因此不需要编译时诊断。名称x
在初始化程序中可见,并引用正在声明的对象。范围在N1570 6.2.1第7段中定义:
任何其他标识符 [除了struct,union或enum标记,或 枚举常量] 具有在完成后立即开始的范围 它的声明者。
在这种情况下,声明者是int x
。
这允许这样的事情:
int x = 10, y = x + 1;
但是声明具有未定义的行为,因为初始化器指的是一个尚未初始化的对象。
行为未定义的明确声明在N1570 6.3.2.1第2段中,该段描述了"转换"左值(指定对象的表达式)与存储在该对象中的值的对比。
除 [不适用于此处的案例列表] 外, 没有数组类型的左值将转换为存储的值 在指定的对象中(并且不再是左值);这就是所谓的 左值转换。
[...]
如果左值指定一个自动存储持续时间的对象 可以使用register
存储类声明(从不 得到了它的地址),并且该对象未初始化(未声明 使用初始化程序并且之前未执行任何赋值 使用),行为未定义。
有问题的对象是x
,在初始化程序中引用。此时,没有为x
分配任何值,因此表达式具有未定义的行为。
实际上,如果启用足够高的警告级别,您可能会收到编译时警告。实际行为可能与省略初始化程序相同:
int x;
但不要指望它。
答案 1 :(得分:2)
根据语言规范
6.7.8.10如果没有明确初始化具有自动存储持续时间的对象,则其值是不确定的。
此外,它说
6.7.8.11标量的初始值设定项应为单个表达式,可选择用大括号括起来。对象的初始值是表达式的初始值(转换后)。
因此,初始化表达式(x
右侧的=
)的值是 indeterminate ,因此我们正在处理未定义的行为,因为初始化程序从变量读取x
具有不确定的价值。
各种编译器提供警告设置以捕获这些条件。
答案 2 :(得分:1)
int x = x;
导致未定义的行为。不要指望任何可预测的行为。
答案 3 :(得分:1)
Clang确实警告过:
$ clang -c -Wall ub_or_not_ub.c
ub_or_not_ub.c:4:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
int x = x;
~ ^
所以我猜它是未定义的行为。