C 我应该重用变量吗?
假设我需要一个计数器(我用C编程),只需要一次。我是否应该重用一个不再需要的变量,而不是声明一个计数器 例如:C 我应该重用变量吗?,c,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; } intmain(){ int-in; //代码在
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;
}
intmain(){
int-in;
//代码在这里
对于(in=0;in有一些编码风格的规则,比如将变量的作用域和生存期限制在其使用范围内。另一个是声明最接近其使用范围的变量
for
循环最惯用的形式是:
for (int i = 0; i < 10; i++) // do something
for(int i=0;i<10;i++)//做点什么
使用:
for(in=0; in<10; in++) // do something
for(in=0;in如果您真的想重用它,您可以重用它,但是对于一个简单的变量,您并没有节省太多(您在堆栈上节省了相同的空间)
出于维护目的,所有变量(以及函数和结构)应该有一个有意义的名称。我假设您希望这样做的原因是为了效率。您可能认为通过重用变量,可以避免额外的不必要的内存分配,从技术上讲,您是对的。您提供的上述代码可以很好地工作,但是重用声明的变量来存储不相关的数据这通常是一种糟糕的编码实践,没有必要
这是一种糟糕的编码实践,因为它使您的代码更难理解和维护,当您将代码交给其他人维护时,这一点就更加正确了。虽然您在堆栈上节省了一些空间,但我认为不值得让您的代码不可读。在您给出的示例中
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;
}
intmain(){
int-in;
//代码在这里
对于(in=0;in这取决于变量名。当两段代码执行类似的操作且变量名仍然良好时,您可以重用它(只要确保代码仍然正确)。但如果变量用于完全不同的目的,这将使代码更难读取。例如,这是可以接受的:
int n;
for (n = 0; n < 10; ++n)
do_something(n);
for (n = 5; n < 100; ++n)
do_something_else(n * 2);
intn;
对于(n=0;n<10;++n)
做某事(n);
对于(n=5;n<100;++n)
做其他事情(n*2);
这种用法很糟糕:
int timeout = get_timeout();
start_timer(timeout);
for (timeout = 0; timeout < 5; ++timeout)
status[timeout] = SUCCESS;
int timeout=get_timeout();
启动定时器(超时);
用于(超时=0;超时<5;++超时)
状态[超时]=成功;
后一个示例应以这种方式重写,以使其更具可读性:
int timeout = get_timeout();
start_timer(timeout);
int n;
for (n = 0; n < 5; ++n)
status[n] = SUCCESS;
int timeout=get_timeout();
启动定时器(超时);
int n;
对于(n=0;n<5;++n)
状态[n]=成功;
这通常取决于代码的性能、大小和维护/可读性。
在大多数情况下,您可能需要维护和可读性,因此您可以使用显式变量名保持代码的清晰性,并且不要重用它们以避免混淆。
在时间关键型代码和/或低资源系统中,您可能希望大量重用,因为您希望避免过多地加载堆栈
如果您的编译器是C99兼容的,您可以使用restrict变量作用域来限制它们的使用,但是要小心,您的编译器可能无法很好地处理这个问题,并且在某些情况下会继续加载堆栈。
在下面的示例中,函数框架的restrict.c堆栈使用率高于gcc 4.8.2中的reuse.c
示例:restrict.c
示例:reuse.disasm
事实上,您可以混合使用这两种语句,声明在函数中重用的通用循环计数器(i、j、k),并显式命名重要的变量。为新对象使用新名称很有用,就像命名人一样。@chux我们不能重用死人的名称吗?:)使用名为“counter”的变量可能有意义在几个地方计数。但是用它来存储,比如说,一磅苹果的成本是没有意义的。@Eugene Sh。当然,但不是我在中理解的那样(我想要的名字是不是已经取了?),我会把“in”改成有意义的东西,并使用它,因为for循环已经在“in”中了低功耗、低ram(堆栈)嵌入式系统的计数器变量您可能希望限制局部变量声明。有人使用宏显式命名共享变量。@rom1nux:OTOH通过缩小堆栈放置变量的范围,您有效地节省了内存,因为其对象占用的空间在其范围结束时立即释放,因此编译器可能会将其用于其他目的。
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;
}
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;
}
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
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