我应该重用变量吗?

时间:2016-06-16 17:28:29

标签: c

让我们说我需要一个计数器(我在C中编程),只需要一次。我应该只重用一个不再需要的变量,而不是声明一个计数器吗?

例如:

int main() {
   int in;

   //code goes here

   for(in=0; in<10; in++)   //do something 
   //instead of using i, I reuse in and use it as a counter

   return 0;
}

5 个答案:

答案 0 :(得分:3)

有编码风格规则,例如限制变量&#39;范围和使用寿命。另一个是声明最接近其用法的变量。

for循环的最惯用形式是:

for (int i = 0; i < 10; i++)    // do something

使用:

for(in=0; in<10; in++)   // do something

可能会误导维护程序员,在in循环的范围之后,for的值被重新

答案 1 :(得分:1)

我假设你想要这样做的原因是效率。您可能认为通过重用变量,您可以避免额外的不必要的内存分配,从技术上讲,您是对的。您提供的上述代码可以正常工作,但重用声明的变量来存储不相关的数据通常是一种糟糕的编码实践并且是不必要的。

这是一种糟糕的编码习惯,因为它会使您的代码更难理解和维护,当您将代码提供给其他人维护时,这变得更加真实。虽然你在堆栈上节省了一些空间,但我认为不值得让你的代码不可读。在你给出的例子中

int main() {
   int in;

   //code goes here

   for(in=0; in<10; in++)   //do something 
   //instead of using i, I reuse in and use it as a counter

   return 0;
}

int in是一个存在于程序堆栈中的整数。 C程序中的整数通常为4个字节。现代操作系统中的size of the stack并不是您需要担心的普通C程序。因此,为了使您的代码更难以维护(无论是您自己还是其他人),唯一的好处是在程序堆栈上节省4个字节。在某些情况下,具体的开发限制可能会使这成为一个很好的权衡,但这很少是真的,除非完全必要,否则不应该这样做。

答案 2 :(得分:0)

如果你真的想要,你可以重复使用它,但你没有为一个简单的变量节省太多(你在堆栈上节省了相同的空间)。

出于维护目的,所有变量(以及函数和结构)都应具有有意义的名称。

答案 3 :(得分:0)

这取决于变量名称。当两段代码执行类似的操作并且变量名仍然很好时,您可以重用它(只要您确保代码仍然正确)。但是如果变量用于完全不同的目的,这将使代码更难以阅读。例如,这是可以接受的:

int n;
for (n = 0; n < 10; ++n)
  do_something(n);
for (n = 5; n < 100; ++n)
  do_something_else(n * 2);

这种用法很糟糕:

int timeout = get_timeout();
start_timer(timeout);

for (timeout = 0; timeout < 5; ++timeout)
  status[timeout] = SUCCESS;

后一个例子应该以这种方式重写,以使其更具可读性:

int timeout = get_timeout();
start_timer(timeout);

int n;
for (n = 0; n < 5; ++n)
  status[n] = SUCCESS;

答案 4 :(得分:0)

这一直取决于代码的性能,大小和维护/可读性。 在大多数情况下,您可能需要维护和可读性,因此您可以使用显式变量名称保持代码清晰,并且不要重复使用它们以避免混淆。 在时间关键代码和/或低资源系统上,您可能希望重复使用很多,因为您希望避免过多地加载堆栈。

如果您的编译器符合C99,您可以使用限制变量作用域来使用它们,但要小心,您的编译器可能无法很好地处理它并在某些情况下继续加载堆栈。 在下面的示例中,函数框架的restrict.c堆栈使用率高于gcc 4.8.2

上的reuse.c

示例:restrict.c

int main(int argc, char** argv)
{
    int a=0;
    for(int i1=0;i1<10;i1++){
        a++;
    }
    for(int i2=0;i2<10;i2++){
        a++;
    }
    for(int i3=0;i3<10;i3++){
        a++;
    }
    for(int i4=0;i4<10;i4++){
        a++;
    }   
    return 0;
}

示例:reuse.c

int main(int argc, char** argv)
{
    int i, a=0;
    for(i=0;i<10;i++){
        a++;
    }
    for(i=0;i<10;i++){
        a++;
    }
    for(i=0;i<10;i++){
        a++;
    }
    for(i=0;i<10;i++){
        a++;
    }   
    return 0;
}

示例:restrict.disasm

main:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $64, %rsp
    .seh_stackalloc 64
    .seh_endprologue
    movl    %ecx, 16(%rbp)
    movq    %rdx, 24(%rbp)
    call    __main
    movl    $0, -4(%rbp)
    movl    $0, -8(%rbp)
    jmp .L2
.L3:
    addl    $1, -4(%rbp)
    addl    $1, -8(%rbp)
.L2:
    cmpl    $9, -8(%rbp)
    jle .L3
    movl    $0, -12(%rbp)
    jmp .L4
.L5:
    addl    $1, -4(%rbp)
    addl    $1, -12(%rbp)
.L4:
    cmpl    $9, -12(%rbp)
    jle .L5
    movl    $0, -16(%rbp)
    jmp .L6
.L7:
    addl    $1, -4(%rbp)
    addl    $1, -16(%rbp)
.L6:
    cmpl    $9, -16(%rbp)
    jle .L7
    movl    $0, -20(%rbp)
    jmp .L8
.L9:
    addl    $1, -4(%rbp)
    addl    $1, -20(%rbp)
.L8:
    cmpl    $9, -20(%rbp)
    jle .L9
    movl    $0, %eax
    addq    $64, %rsp
    popq    %rbp
    ret

示例:reuse.disasm

main:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $48, %rsp
    .seh_stackalloc 48
    .seh_endprologue
    movl    %ecx, 16(%rbp)
    movq    %rdx, 24(%rbp)
    call    __main
    movl    $0, -8(%rbp)
    movl    $0, -4(%rbp)
    jmp .L2
.L3:
    addl    $1, -8(%rbp)
    addl    $1, -4(%rbp)
.L2:
    cmpl    $9, -4(%rbp)
    jle .L3
    movl    $0, -4(%rbp)
    jmp .L4
.L5:
    addl    $1, -8(%rbp)
    addl    $1, -4(%rbp)
.L4:
    cmpl    $9, -4(%rbp)
    jle .L5
    movl    $0, -4(%rbp)
    jmp .L6
.L7:
    addl    $1, -8(%rbp)
    addl    $1, -4(%rbp)
.L6:
    cmpl    $9, -4(%rbp)
    jle .L7
    movl    $0, -4(%rbp)
    jmp .L8
.L9:
    addl    $1, -8(%rbp)
    addl    $1, -4(%rbp)
.L8:
    cmpl    $9, -4(%rbp)
    jle .L9
    movl    $0, %eax
    addq    $48, %rsp
    popq    %rbp
    ret

实际上你可以混合使用两个语句,声明在你的函数中重用的一般循环计数器(i,j,k),并保持显式命名的重要意义变量。