C 嵌套范围变量情况下的异常行为
我熟悉C语言中的嵌套作用域规则,其中嵌套块中的相同变量名会遮挡具有相同名称的外部变量。 但是对于下面的代码片段,我无法确定输出的解释C 嵌套范围变量情况下的异常行为,c,gcc,scope,C,Gcc,Scope,我熟悉C语言中的嵌套作用域规则,其中嵌套块中的相同变量名会遮挡具有相同名称的外部变量。 但是对于下面的代码片段,我无法确定输出的解释 #include <stdio.h> int main() { int x = 1, y = 2, z = 3; printf(" x = %d, y = %d, z = %d \n", x, y, z); { int x = 10; float y = 20; printf("
#include <stdio.h>
int main()
{
int x = 1, y = 2, z = 3;
printf(" x = %d, y = %d, z = %d \n", x, y, z);
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
return 0;
}
#包括
int main()
{
int x=1,y=2,z=3;
printf(“x=%d,y=%d,z=%d\n”,x,y,z);
{
int x=10;
浮动y=20;
printf(“x=%d,y=%f,z=%d\n”,x,y,z);
}
{
int z=100;
printf(“x=%d,y=%f,z=%d\n”,x,y,z);
}
返回0;
}
上述代码段的输出为:
x=1,y=2,z=3
x=10,y=20.000000,z=3
x=1,y=20.000000,z=2
请大家帮助我理解第三个printf语句中的y
值是如何产生超出范围的变量值的
首先,我认为它可能是垃圾值,因为使用%f
打印整数会产生垃圾值,因此将内部范围中的y
的值更改为其他值会产生与输出相同的值,因此我确认它不是垃圾值
我使用gcc版本6.3.1 20161221(Red Hat 6.3.1-1)(gcc)编译了该程序,还使用各种在线编译器编译了该程序。问题在于格式说明符和提供的参数不匹配。让我们仔细看看 在第一个内部范围内
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
printf(" x = %d, y = %f, z = %d \n", x, y, z);
^^^^^^
y
被(重新)定义为float
,使用该变量作为%f
转换说明符的参数是完全正确的。但是,一旦作用域结束,(visble)y
再次成为int
。因此在第二个内部范围内
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
printf(" x = %d, y = %f, z = %d \n", x, y, z);
^^^^^^
使用%f
是错误的,并会导致错误。必须使用%d
在此处打印y
的值
相关,引用第§6.2.1/P4章C11
每个其他标识符的作用域由其声明的位置决定(在
声明符或类型说明符)
[……]
如果声明符或类型说明符
声明标识符显示在块内或中的参数声明列表中
一个函数定义,标识符具有块作用域,它终止于
关联块
[……]
如果标识符以相同的名称指定两个不同的实体
空间,范围可能重叠。如果是这样,一个实体的范围(内部范围)将结束
严格优先于其他实体的范围(外部范围)。在内部范围内
标识符指定在内部范围中声明的实体;外部文件中声明的实体
范围在内部范围内隐藏(不可见)
以及与UB相关的第§7.21.6.1章
[…]如果有任何论点
对应转换规范的类型不正确,行为为
未定义
您有一个未定义的行为:
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, y, z); // here y is an int
}
如果printf()
中的标志与良好类型不匹配,则这是未定义的bahavior
您必须使用%d
标志
{
int z = 100;
printf(" x = %d, y = %d, z = %d \n", x, y, z); // here y is an int
}
首先,我认为它可能是垃圾值,因为使用%f打印整数会导致垃圾值,因此将内部范围中的y值更改为其他值会导致与输出相同的值,因此我确认它不是垃圾值
这是一个错误的假设。它是“垃圾”,因为这里有未定义的行为
我引用自己对未定义行为的解释:
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, y, z); // here y is an int
}
C中未定义的行为
C是一种非常低级的语言,其结果如下:
没有什么能阻止你做一些完全错误的事情
许多语言,特别是针对某些托管环境的语言,如Java
或者当你做了不被允许的事情时,比如说,
访问不存在的数组元素<代码>C
没有。只要你
程序语法正确,编译器不会抱怨。如果你这样做
程序中禁止的内容,C
只调用
程序未定义。这正式允许在运行时发生任何事情
节目。通常,结果将是崩溃或只是“垃圾”的输出
值,如上所示。但是如果你真的不走运,你的程序看起来会
直到它得到一些稍微不同的输入,然后
一段时间后,你将很难找到你的程序的确切位置
未定义。因此,请务必避免未定义的行为
另一方面,未定义的行为也可能导致安全漏洞。这
在实践中发生了很多事情
您遇到了一种情况,程序似乎执行了类似于正确执行的操作,这是运气不好
但它是未定义的,作为证明,请使用您未修改的代码查看我的机器上发生的情况:
$/范围
x=1,y=2,z=3
x=10,y=20.000000,z=3
x=1,y=0.000000,z=3
旁注:虽然阴影是定义良好的,但您也应该避免它。创建带有阴影的错误代码是有风险的,因为尽管编译器没有问题,您开始混淆变量。尝试下面代码中的方法!;) 问题如其他答案所示。您忘记了在范围内
y
变量是int
#include <stdio.h>
int main()
{
int x = 1, y = 2, z = 3;
printf(" x = %d, y = %d, z = %d \n", x, y, z);
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, (float)y, z);
}
return 0;
}
#包括
int main()
{
int x=1,y=2,z=3;
printf(“x=%d,y=%d,z=%d\n”,x,y,z);
{
int x=10;
浮动y=20;
printf(“x=%d,y=%f,z=%d\n”,x,y,z);
}
{
int z=100;
printf(“x=%d,y=%f,z=%d\n”,x,(float)y,z);
}
返回0;
}
未定义的行为