嵌套范围变量的异常行为

Shu*_*tra 2 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(" 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;
}
Run Code Online (Sandbox Code Playgroud)

上述代码段的输出是:

x = 1,y = 2,z = 3

x = 10,y = 20.000000,z = 3

x = 1,y = 20.000000,z = 2

有人请帮助我理解y第三个printf语句中的值是如何产生超出范围的变量值的.

首先我认为它可能是垃圾值,因为打印整数并%f导致垃圾值,因此将y内部范围中的值更改为其他值导致与输出相同的值,因此我确认它不是垃圾值.

我使用gcc版本6.3.1 20161221(Red Hat 6.3.1-1)(GCC)编译了程序,并使用各种在线编译器编译了程序.

Sta*_*eur 10

您有一个未定义的行为:

{
    int z = 100;
    printf(" x = %d, y = %f, z = %d \n", x, y, z); // here y is an int
}
Run Code Online (Sandbox Code Playgroud)

如果您的标志printf()与良好类型不匹配,则这是未定义的行为.

你必须使用%d旗帜.

{
    int z = 100;
    printf(" x = %d, y = %d, z = %d \n", x, y, z); // here y is an int
}
Run Code Online (Sandbox Code Playgroud)


Sou*_*osh 8

问题是格式说明符和提供的参数不匹配.让我们仔细看看.

在第一个内部范围

{
    int x = 10;
    float y = 20;

    printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
Run Code Online (Sandbox Code Playgroud)

y是(重新)定义为float并使用该变量作为%f转换说明符的参数是完全正常的.然而,一旦范围结束,(该visble)yint,一次.因此在第二个内部范围内

 printf(" x = %d, y = %f, z = %d \n", x, y, z);
                  ^^^^^^
Run Code Online (Sandbox Code Playgroud)

使用%f是错误的并导致未定义的行为.您必须使用它%d来打印y那里的值.

相关的,引用C11,章节§6.2.1/ P4

每个其他标识符的范围由其声明的位置(在声明符或类型说明符中)确定.

[...]

如果声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表中,则标识符具有块作用域,该作用域终止于关联块的末尾.

[....]

如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠.如果是这样,一个实体(内部范围)的范围将严格地在另一个实体(外部范围)的范围之前结束.在内部范围内,标识符指定在内部范围内声明的实体; 在外部作用域中声明的实体在内部作用域内隐藏(并且不可见).

并且,与章节§7.21.6.1相关的UB

[...]如果任何参数不是相应转换规范的正确类型,则行为未定义.