如果使用goto语句跳转到块的中间,那么该块内的自动变量将不会被初始化。
那么在下面的代码中,如果可以访问/声明i,为什么它没有被初始化?
int main()
{
goto here;
{
int i=10;
here:
printf("%d\n",i);
}
return 0;
}
提示:输出结果是一些垃圾值。
int main()
{
goto here;
{
int i=10;
here:
printf("%d\n",i);
}
return 0;
}
提示:输出结果是一些垃圾值。
你的问题“如果可以访问i,为什么......”没有任何逻辑。能够“访问i”不是支持或反对任何事情的论据。它只意味着printf
语句与i处于相同的作用域。但是,由于你跳过了初始化程序,这个变量是未初始化的(就像你的教程中所说的一样)。
读取未初始化的变量是未定义行为,因此你的程序是不合法的。
变量i的内存已经在编译时设置好了,因为变量已知存在于内部块中。这个内存并没有动态分配,就像你想象的那样。它已经存在,但由于goto
,它从未设置为任何确定的值。
经验法则:不要跨过初始化程序。
i
的内存已经在编译时分配”(可能会误导):i
是一个本地变量,每次调用函数时都会在堆栈上创建空间,并在函数退出时恢复堆栈 - 编译器添加了代码来在堆栈上创建空间并将变量替换为该空间的地址,在这种情况下是[rbp-4]
,其中4是int的大小。 - slashmais{}
之间),与该作用域内语句的执行顺序无关。goto
跳过了 i
的初始化,这意味着当调用 printf()
时它具有未定义的值。int main()
{
int i; //i is declared, but not initialized
goto here;
{
i=10;//i is initialized
here: //you've skipped the initialization
printf("%d\n",i);//and got garbage
}
return 0;
}
针对你的情况:
int main()
{
goto here;
{
//printf("%d\n",i); // i does not exist here yet
int i; //from here until the end of the scope variable i exists
i=10; // i exists here and smth is written into it
here: // i exists here
printf("%d\n",i); // i exists here and it's value is accessed
}
return 0;
}
所以,int i = 5;
这其实是两件事情。第一是声明,它不能被任何东西跳过,包括 goto
(就像打开新作用域也不受影响一样。你已经跳到了作用域的中间,但该作用域已经存在)。第二是操作赋值,由于它是正常的操作(程序流程),因此可以被 goto
、'break'、'continue' 或 'return' 跳过。
=
表示。只需尝试int a[3]; a = { 1, 2, 3};
与int a[3] = {1, 2, 3};
进行比较就可以了。 - dmckee --- ex-moderator kittenC编译器将解析源文件并“记录”任何变量初始化。
当它到达
printf("%d\n", i)
它将知道变量i已经存在,因此应该能够使用它,因为它在作用域内。
在执行空间中,在调用main函数之后,在main()代码的任何执行之前,栈上为i变量保留了空间。
因为语言标准规定:
6.7.8 初始化
语义
如果一个具有自动存储期的对象没有被显式初始化,则其值是不确定的。
J.2 未定义行为
在以下情况下,行为是未定义的:
在具有自动存储期的对象的值不确定时使用该对象的值。
6.8.4.2 switch语句
例子:在人工程序片段中
switch (expr)
{
int i = 4;
f(i);
case 0:
i = 17;
/* falls through into default code */
default:
printf("%d\n", i);
}
标识符为 i 的对象具有自动存储期(在块内),但从未被初始化。因此,如果控制表达式具有非零值,则对 printf 函数的调用将访问一个不确定的值。类似地,无法访问函数 f。
C语言允许您访问地址空间中的任何内容,无论它是否被初始化。有时候这样做会导致程序崩溃或显示垃圾数据,有时候也可能会打印出一些有用的信息,但这都是未定义的行为。这是一个方便的技巧,但也是破坏程序的好方法,所以不要认为只要得到结果就意味着您的技巧有效。
return i;
而不是return 0;
,那么C语言将不允许你从任何地方访问到任何东西。这个问题似乎是关于如何让变量i
处于作用域但未初始化,而不是关于使用指针漫游地址空间时C语言慷慨地为你提供自我脚射的机会。 - Steve Jessop