Consider the following C program
考虑下面的C程序
#include <stdio.h>
typedef struct s {
int x;
} s_t;
int main() {
int x;
s_t a;
scanf("%d", &x);
if (x > 0) {
s_t a;
a.x = x;
}
printf("%d\n", a.x);
}
The a
struct variable in the if branch clearly shadows the a
struct variable in main. One would expect that the output in printf would be undefined, but with GCC the scoped variable seems to equal the main variable.
if分支中的a struct变量在主结构变量中明显地阴影了a struct变量。可以预期printf中的输出将是未定义的,但是对于GCC,作用域变量似乎等于主变量。
For example
例如
gcc test.c -o test
echo 10 | ./test
will output 10.
将输出10。
On the other hand, running this through clang, does as expected
另一方面,通过clang运行它,就像预期的那样
clang test.c -o test
echo 10 | ./test
outputs -2145248048.
输出-2145248048。
Is this a GCC bug or is there some sort of undefined behaviour that this is triggering?
这是一个GCC bug,还是它引发了某种未定义的行为?
gcc 4.8.2 clang 3.4
gcc 4.8.2叮当声3.4
4 个解决方案
#1
9
As others mentioned, you're reading an uninitialized local variable and that's undefined. So, anything is legit. Having said that, there is a particular reason for this behavior: gcc
reuses variables on the stack as much as it can (i.e., as long as the generated code is provably correct). You can fine-tune using the -fstack-reuse
option.
正如其他人提到的,您正在读取一个未初始化的局部变量,这是未定义的。所以,任何事都是合法的。话虽如此,这种行为有一个特殊的原因:gcc尽可能多地重用堆栈上的变量(例如。,只要生成的代码被证明是正确的)。您可以使用-fstack-重用选项进行微调。
To disable stack reuse:
禁用堆栈重用:
gcc test.c -o test -fstack-reuse=none
echo 10 | ./test
4195808 # prints some random number.
To enable stack reuse for all variables:
为所有变量启用堆栈重用:
gcc test.c -o test -fstack-reuse=all #, or -fstack-reuse=named_vars
echo 10 | ./test
10 # prints 10, as it reuses the space on the stack.
This is fully documented on GCC Code Generation Options.
这在GCC代码生成选项中有完整的文档说明。
#2
4
One would expect that the output in printf would be undefined
可以预期printf中的输出将是未定义的
It is undefined. Undefined behaviour means that anything can happen, including (but not limited to) any particular output.
这是未定义的。未定义的行为意味着任何事情都可能发生,包括(但不限于)任何特定的输出。
In this case what's likely happening is that the compiler optimizes both a
to have the same address.
在这种情况下,可能发生的情况是编译器优化两个a具有相同的地址。
#3
4
No compiler bug, your program invokes undefined behavior.
没有编译器错误,您的程序调用未定义的行为。
You are reading an uninitialized automatic object and C says it has indeterminate value and that reading it is undefined behavior.
您正在读取一个未初始化的自动对象,C表示它具有不确定的值,而读取它是未定义的行为。
Give a.x
(the one declared in main
scope) a value to give your program a specified behavior.
给一个。x(主作用域中声明的值)为程序指定的行为。
#4
3
Is this a GCC bug or is there some sort of undefined behavior that this is triggering?
这是一个GCC bug还是它引发了某种未定义的行为?
It's undefined behavior. s_t a;
in the if
statement hides the previous declaration of a
.
In the block
未定义的行为。s_t;在if语句中隐藏了块中a.的先前声明
if (x > 0) {
s_t a;
a.x = x;
}
x
is assigned to the local a.x
. After this block, a
is no longer available and in printf
you are accessing an uninitialized variable. Uninitialized variables may invoke UB.
x被分配给本地a.x。在此块之后,a不再可用,在printf中,您正在访问一个未初始化的变量。未初始化的变量可能会调用UB。
#1
9
As others mentioned, you're reading an uninitialized local variable and that's undefined. So, anything is legit. Having said that, there is a particular reason for this behavior: gcc
reuses variables on the stack as much as it can (i.e., as long as the generated code is provably correct). You can fine-tune using the -fstack-reuse
option.
正如其他人提到的,您正在读取一个未初始化的局部变量,这是未定义的。所以,任何事都是合法的。话虽如此,这种行为有一个特殊的原因:gcc尽可能多地重用堆栈上的变量(例如。,只要生成的代码被证明是正确的)。您可以使用-fstack-重用选项进行微调。
To disable stack reuse:
禁用堆栈重用:
gcc test.c -o test -fstack-reuse=none
echo 10 | ./test
4195808 # prints some random number.
To enable stack reuse for all variables:
为所有变量启用堆栈重用:
gcc test.c -o test -fstack-reuse=all #, or -fstack-reuse=named_vars
echo 10 | ./test
10 # prints 10, as it reuses the space on the stack.
This is fully documented on GCC Code Generation Options.
这在GCC代码生成选项中有完整的文档说明。
#2
4
One would expect that the output in printf would be undefined
可以预期printf中的输出将是未定义的
It is undefined. Undefined behaviour means that anything can happen, including (but not limited to) any particular output.
这是未定义的。未定义的行为意味着任何事情都可能发生,包括(但不限于)任何特定的输出。
In this case what's likely happening is that the compiler optimizes both a
to have the same address.
在这种情况下,可能发生的情况是编译器优化两个a具有相同的地址。
#3
4
No compiler bug, your program invokes undefined behavior.
没有编译器错误,您的程序调用未定义的行为。
You are reading an uninitialized automatic object and C says it has indeterminate value and that reading it is undefined behavior.
您正在读取一个未初始化的自动对象,C表示它具有不确定的值,而读取它是未定义的行为。
Give a.x
(the one declared in main
scope) a value to give your program a specified behavior.
给一个。x(主作用域中声明的值)为程序指定的行为。
#4
3
Is this a GCC bug or is there some sort of undefined behavior that this is triggering?
这是一个GCC bug还是它引发了某种未定义的行为?
It's undefined behavior. s_t a;
in the if
statement hides the previous declaration of a
.
In the block
未定义的行为。s_t;在if语句中隐藏了块中a.的先前声明
if (x > 0) {
s_t a;
a.x = x;
}
x
is assigned to the local a.x
. After this block, a
is no longer available and in printf
you are accessing an uninitialized variable. Uninitialized variables may invoke UB.
x被分配给本地a.x。在此块之后,a不再可用,在printf中,您正在访问一个未初始化的变量。未初始化的变量可能会调用UB。