C 声明差异和范围?
在这个问题上,有人问这两者之间有什么区别C 声明差异和范围?,c,C,在这个问题上,有人问这两者之间有什么区别 int i; for (i=0; i<100; i++) { //some loop.... } “新的”i是否会用“旧的”i初始化?或者旧的i已经无法访问,因为新的i已经被声明了吗?否,在任何上下文中 int i=i; int tmp=i, i=tmp; 这是个坏主意,因为第二个i与第一个对象是同一个对象,但仍然没有初始化 如果你坚持的话,你可以这样做 int i=i; int tmp=i, i=tmp; 以获得所需的效果。在
int i;
for (i=0; i<100; i++) {
//some loop....
}
“新的”
i
是否会用“旧的”i
初始化?或者旧的i
已经无法访问,因为新的i
已经被声明了吗?否,在任何上下文中
int i=i;
int tmp=i, i=tmp;
这是个坏主意,因为第二个i
与第一个对象是同一个对象,但仍然没有初始化
如果你坚持的话,你可以这样做
int i=i;
int tmp=i, i=tmp;
以获得所需的效果。在此for循环语句中
int i = 32;
for (int i = i; i < 100; i++) {
// some loop
}
变量i在=
的右侧引用自身
另一个类似的例子。假设您有一个typedef
typedef int Int;
你可以根据它的定义来写
Int Int;
在这种情况下,类型为Int
的对象的名称Int
隐藏了typedef定义,您可能还没有写入
Int Another_Int;
因为编译器将发出一个错误
根据C标准(6.2.1标识符范围)
4…If声明程序或声明
标识符出现在块内或参数列表内
函数定义中的声明,标识符具有块范围,
在关联块的末尾终止
一个更清晰的写在C++标准(3.3.2点声明)
1名称的声明点紧随其名称之后 完整声明人(第8条)及其初始值设定人(如有)之前, 除非下文另有说明。[示例: 这里,第二个x用它自己的(不确定)值初始化。 -[结束示例] 在这段代码片段中要考虑到这一点int i = 10;
{
int i[i];
}
在复合语句中有声明的数组inti[10]
即外部变量i
用作数组大小,因为内部变量i
只有在其声明符完成时才会声明。请参见:“如果子句-1是声明,则它声明的任何标识符的范围都是声明的剩余部分和整个循环,包括其他两个表达式”
第二个i
是指正在定义的i
,而不是旧的
整个过程都是UB,因为您使用的是i
(在循环中定义的i
)的值,而没有先前的赋值(或初始化)
使用工作(但不同)示例进行编辑 您仍然可以通过使用指针来使用旧值
int i = 42;
int *old_i = &i;
for (int i = *old_i; i < 50; i++) printf("%d ", i);
inti=42;
int*old_i=&i;
对于(int i=*old_i;i<50;i++)printf(“%d”,i);
多亏了Jens Gustedt,我做了更多的研究,以下是我的发现:以下代码:
#include<stdio.h>
int main()
{
int i = 32;
for (int i=i; i<50; i++) {
printf("Hello World %d", i); // <-- this is the new i, the other one is not accessible here
}
return 0;
}
用于循环的变量为
[rbp-4]
,未初始化,可以是任何形式。所以它确实是一个UB “整件事都是UB”因为?整件事都是UB。。。由于您使用的是i
的值,而没有先前的赋值(或初始化),因此本标准的引用无法确定新的i
是在零件int i
之后可见,还是仅在初始化int i=i之后完成子句时可见
@PaulOgilvie:我把“声明的剩余部分”理解为以=
=>开头的部分(int I/*我们现在在声明的剩余部分*/=I;…
之前)。L3应该是[rbp-4]
和[rbp-8]的初始化
。它不在那里,所以编译器显然使用了新的i
。因为用它自己初始化没有效果,指令已经优化了。清楚&谢谢。@PaulOgilvie我很高兴你提出了这个问题,你今天让我不那么笨了:)嗯:标准允许实现使用旧i
的值;但它仍然是UB:-)我的意思是:使用编译器输出作为确定表达式有效性的基础不是一个好方法。您的第一个示例很有趣,因为它意味着声明优先于定义。编译器在声明Int时也可能出现错误代码>你的第二个例子也很有趣,或多或少是我在最初的问题中所期望的:只有在子句完成后,新变量才会被调用到生命中(但这不是真的)。
int i = 42;
int *old_i = &i;
for (int i = *old_i; i < 50; i++) printf("%d ", i);
#include<stdio.h>
int main()
{
int i = 32;
for (int i=i; i<50; i++) {
printf("Hello World %d", i); // <-- this is the new i, the other one is not accessible here
}
return 0;
}
.LC0:
.string "Hello World %d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-8], 32
.L3:
cmp DWORD PTR [rbp-4], 49
jg .L2
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
add DWORD PTR [rbp-4], 1
jmp .L3
.L2:
mov eax, 0
leave
ret