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