C++中在for循环中声明int

12

我有一段时间没有使用C++了。我一直依赖我的Java编译器来进行优化。

在C++中,做一个for循环最优的方法是什么?或者现代编译器都一样吗?在“旧日子”里是不同的。

for (int i=1; i<=100; i++)

或者

int i;
for (i=1; i<=100; i++)

int i = 1;
for ( ; i<=100; i++)

在C语言中是一样的吗?

编辑:好的,压倒性的共识是使用第一个情况,并让编译器如果需要的话进行优化。

10个回答

12

我认为像这样的琐碎问题可能已经被编译器优化了,你不必担心。 第一种选项最易读,所以你应该使用它。

编辑:根据其他答案提供的信息,还有一个区别是,如果你在循环初始化中声明变量,它将在循环结束后停止存在。


2
关于你的编辑,这取决于编译器。我见过至少一种编译器(MSVC++6.0),在循环结束后变量并不会消失。 - Jeff Barger
2
@Jeff 标准兼容的编译器将限制 for 循环中变量 i 的作用域,但是像 MSVC++ 6.0 这样的旧编译器则不会。因此,如果您使用旧编译器,则需要注意这一点。然而,根据语言标准,作用域应该被限制在 for 循环内部。近期的编译器在这方面应该能够正确地处理。 - Jonathan M Davis
在MSVC上,可以使用“#define for if(0) {} else for”这个技巧来获得正确的行为。啊,是的,那些美好的日子…… - Dan Olson

11

区别在于作用域。

for(int i = 1; i <= 100; ++i)

通常更好,因为这样i的作用域被限制在for循环内部。如果你在for循环之前声明它,那么它会在for循环结束后继续存在,并可能与其他变量发生冲突。如果你只在for循环中使用它,那么没有理由让它存在更长的时间。


在一些旧编译器中,i 的作用域是到函数的结尾。将 int 移出循环可以让你在其他编译器中保持良好。 - EvilTeach
@EvilTech 只有旧的、不兼容的编译器才会出现这个问题。所以,除非你认为你的代码很可能会与这样的编译器一起使用,否则不用担心。如果确实存在问题,那么在 for 循环周围加上额外的一对大括号就可以解决问题。 - Jonathan M Davis

8

假设原帖作者有一个循环,他非常想要优化 - 每个指令都很重要。我们如何通过实证的方法找到他的问题的答案?

至少gcc有一个有用但不常用的开关'-S'。它会转储.c文件的汇编代码版本,并可用于回答像OP提出的问题。我写了一个简单的程序:

int main( )
{
    int sum = 0;

    for(int i=1;i<=10;++i)
    {
        sum = sum + i;
    }
    return sum;
}

运行命令:gcc -O0 -std=c99 -S main.c,生成主程序的汇编版本。以下是main.s文件的内容(已删去部分冗余内容):

    movl    $0, -8(%rbp)
    movl    $1, -4(%rbp)
    jmp     .L2
.L3:
    movl    -4(%rbp), %eax
    addl    %eax, -8(%rbp)
    addl    $1, -4(%rbp)
.L2:
    cmpl    $10, -4(%rbp)
    jle     .L3

你不需要成为汇编专家来理解正在发生的事情。movl移动值,addl添加东西,cmpl比较,jle代表“跳转到小于”,$代表常量。它将0加载到某个地方-那一定是“sum”,将1加载到另一个地方-啊,是“i”!跳转到L2进行比较,再跳转到L3进行添加。再次落入L2进行比较。很整洁!这是一个for循环。
将程序更改为:
int main( )
{
    int sum = 0;
    int i=1;
    for( ;i<=10;++i)
    {
        sum = sum + i;
    }
    return sum;
}

重新运行gcc,生成的汇编代码非常相似。由于记录了行号等信息,因此它们不会完全相同,但是最终的汇编代码是相同的。在最后一个案例中也是如此。因此,即使没有优化,代码也基本相同。
为了好玩,使用“-O3”而不是“-O0”重新运行gcc以启用优化,并查看.s文件。
main:
movl    $55, %eax
ret

gcc不仅知道我们正在进行一个for循环,而且还意识到它将在编译时运行固定次数的循环,并为我们执行了循环,扔掉了“i”和“sum”,并硬编码了答案-55!那很快-尽管有点牵强。

故事的寓意是什么?花时间确保您的代码清洁且设计良好。编写易读且易于维护的代码。那些靠着山露和奇多饼干生活的家伙比我们聪明得多,并且已经为我们解决了大部分这些简单的优化问题。玩得开心!


4

这是一样的。编译器会将它们优化为相同的内容。

即使它们不同,与循环实际体的差异也可以忽略不计。您不应该担心微小的优化问题。除非您正在性能分析以查看它是否有影响,否则不应进行微小的优化。


3

就速度而言,这两种写法没有区别。如果你不会再次使用 i,编译器会进行优化。

就风格而言,我会把定义放在循环结构中,因为这样可以减少后面定义另一个 i 时出现冲突的风险。


2
不要担心微小的优化,让编译器去做。选择最易读的方式。注意,在for初始化语句中声明变量将该变量限定于for语句的范围内(C++03 § 6.5.3 1),尽管编译器的确切行为可能会有所不同(某些编译器可供选择)。如果循环外的代码使用该变量,请在循环外声明它。如果变量真正只在循环中使用,请在初始化程序中声明它。

1
for(int i = 1; i <= 100; ++i)

这是最容易阅读的,除了 ANSI C / C89 不支持。


1

已经提到两者之间的主要区别是作用域。确保您了解编译器如何处理声明为 int 的变量的作用域。

for (int i = 1; ...;...)

我知道在使用MSVC++6时,变量i在循环外仍然在作用域内,就像它是在循环之前声明的一样。这种行为与VS2005不同,我需要检查一下,但我认为在我使用的最后一个版本的gcc中也是如此。在这两个编译器中,该变量只在循环内部有效。


这是VC++6中一个众所周知的bug。如果你真的在意,就用另一组大括号将for循环包围起来。 - jmucchiello

0

C++ 的 for 循环本质上就是一个封装好的 while 循环。

for (int i=1; i<=100; i++)
{
    some foobar ; 
}

对于编译器而言,上述代码与下面的代码完全相同。

{ 
int i=1 ;
    while (i<=100){
        some foobar ;
        i++ ; 
    }
}

请注意,int i=1;被包含在一个专用范围内,该范围仅包括它和while循环。

-1

都一样。


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