在C语言中重新声明变量

12

我看到有类似的问题关于C++,在C++中重新声明变量会产生任何影响吗?

那么在C语言中呢?重新声明变量会有任何显著影响吗?这通常被认为是代码组织不良吗?

for(;;) {
   int y = 1 + 2 + 3; // some kind of repeated redeclaration? 
}

编辑:

完善我的问题。

如果我在一个函数中有一个循环,那么重复调用“int y = 1 + 2 + 3;”是否允许?会引起问题吗?它是什么作用,声明一次y


1
改进了我的问题。 - visc
@5gon12eder,循环并不重要。它们可以只是顺序重新声明。int y = 1; int y = 2; int y = 3;这里会发生什么是我的问题。 - visc
那个后面的例子会是一个语义错误,并被编译器拒绝。如果你不确定代码确切的作用,就要特别注意我们讨论的是哪个例子。 - 5gon12eder
2
你的问题示例中没有不允许重新声明,因为一开始只有一个声明。我猜想你的问题实际上更多关于作用域而非性能。 - 5gon12eder
1
我认为我的编辑中所询问的内容非常清楚。当在循环中第一次和随后的几次调用该特定行时会发生什么? - visc
显示剩余5条评论
2个回答

14

C 语言有变量作用域的概念。简而言之,每对 {} 引入一个新的作用域,并且变量绑定到这些作用域中。你可以使用相同名称的变量,只要它们在不同的作用域中即可。

这就是为什么下面的代码是有效的:

if(...) {
    int y; # y is valid here
}          # end of scope, y is not valid here
if(...) {  # new scope
    int y; # That's another y
}

那是无效的:

if(...) {
    int y;
    int y; # error, redeclaration
}

此外,声明是源代码属性,而不是运行时程序属性。

因此,如果您写入:

for(;;) {
   int y = 1 + 2 + 3;
}

你只需声明y 一次(因为你只写了一次),而不是无限次数。


7

大多数C编译器会尽可能地进行优化。如果您想真正了解情况,请使用标志编译以查看汇编代码并查看它正在执行的操作。就像有人说的那样,如果它是一个简单类型(没有构造函数),特别是如果您使用所有文字,编译器可能只会将一个固定值移动到每个迭代的寄存器中,或者如果在迭代之间没有任何变量更改,则甚至不会费心。

我刚刚检查了您下面显示的示例,并将其更改为在循环中修改变量,您可以看到生成的汇编代码如何更改。

在第一个示例中,请注意LBB0_1处的循环,它只是一个movl指令。

在第二个示例中,它仍然非常简单,但即使结果未被使用,它仍然会保存堆栈上的内容。我添加了一些注释来解释循环正在做什么。

$ cc -fno-asynchronous-unwind-tables -S dummy.c

int main(void) { 
    for(;;) {
        int y = 1 + 2 + 3;
    }
}

$ cat dummy.s

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 12
    .globl  _main
    .align  4, 0x90
_main:                                  ## @main
## BB#0:
    pushq   %rbp
    movq    %rsp, %rbp
    movl    $0, -4(%rbp)
LBB0_1:                                 ## =>This Inner Loop Header: Depth=1
    movl    $6, -8(%rbp)
    jmp LBB0_1

.subsections_via_symbols

$ cc -fno-asynchronous-unwind-tables -S dummy.c

int main(void) { 
    int i = 0;
    for(;;) {
        int y = i + 2 + 3;
        i++;
    }
}

$ cat dummy.s

        .section        __TEXT,__text,regular,pure_instructions
        .macosx_version_min 10, 12
        .globl  _main
        .align  4, 0x90
_main:                                  ## @main
## BB#0:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $0, -4(%rbp)            
        movl    $0, -8(%rbp)            ## i = 0
LBB0_1:                                 
        movl    -8(%rbp), %eax          ## y = i
        addl    $2, %eax                ## y += 2
        addl    $3, %eax                ## y += 3
        movl    %eax, -12(%rbp)         ## -12(rbp) = y
        movl    -8(%rbp), %eax          ## eax = i
        addl    $1, %eax                ## i++
        movl    %eax, -8(%rbp)          ## -8(rbp) = i
        jmp     LBB0_1

.subsections_via_symbols

谢谢,这非常有用。 - visc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接