10

考虑 C 中的以下代码:

void main()
{
    int a=0;

    for(printf("\nA"); a; printf("\nB"));

    printf("\nC");
    printf("\nD");     
}

当我使用 Turb C++ 3.0 版和 gcc-4.3.4 编译它时,我得到以下两种情况的输出:

A
C
D

但是,如果我编译以下代码:

void main()
{
    for(printf("\nA"); 0; printf("\nB"));

    printf("\nC");
    printf("\nD");
}

gcc-4.3.4 的输出与前一种情况相同,但 turbo c++ 3.0 产生以下输出:

A
B
C
D

首先,我不知道这里发生了什么!另外,为什么 gcc 编译器的输出对于两个代码是相同的,但是在 turboc++ 3.0 编译器的情况下,输出是不同的?有人可以阐明一下吗?

编辑 :

其实有人在IT公司的面试中被问到这个问题,当他没有给出答案时,面试官给出了这个解释。但我觉得这很愚蠢。您如何要求某人使用“错误”,就好像它是该语言提供的“设施”一样?为了将其称为“设施”和“技术”,无论我们在第二个表达式中将 0 作为文字传递还是将值为 0 的变量传递,结果应该是相同的。

我是否认为面试官非常愚蠢地提出这样的问题并且这表明他的无能是错误的?

4

5 回答 5

12

第二个例子的 TCC 输出是错误的。

来自 C99 标准:

该声明

for ( 子句 1 ; 表达式 2 ; 表达式 3 ) 语句

行为如下: 表达式expression-2是在每次执行循环体之前计算的控制表达式。每次执行循环体后,表达式expression-3被评估为 void 表达式。[...]

显然,这里没有迭代,所以永远不应该执行表达式 3 。

同样,在 C90 标准中(或至少在我发现的草案中),它说:

除了循环体中 continue 语句的行为外,该语句

     for (  expression-1 ;  expression-2 ;  expression-3 )  statement

和语句的顺序

      expression-1 ;
     while ( expression-2) {
               statement
              expression-3 ;
     }

是等价的。

于 2012-06-18T16:15:46.573 回答
3

Turbo C++ 3.0 于 1990 年代发布,随后很快发布了 3.1。

我猜你的古老编译器有很多错误,这些错误更新很快。此外,它可能没有这样的错误,但可能已经发出了优化的组件,在新的管道内衬架构下失败了。

无论如何,保证您当前的平台不支持Turbo C++ 3.0 。当涉及到由于平台是在近 20 年后创建的而不受支持的编译器时,您不能因为发出错误的程序而真正责怪它。

于 2012-06-18T16:19:45.200 回答
2

gcc 输出是正确的。

第一种情况下的 Turbo C++ 3.0 输出是正确的。

第二种情况下的 TurboC++ 3.0 输出是错误的。

您似乎在 Turbo C++ 3.0 编译器中发现了导致错误代码生成的边缘情况。

C 或 C++ 中的 for-stmt 具有一般语法

for ( 初始化 ; 测试 ; 重新初始化 ) stmt

初始化在循环开始之前执行一次。测试在循环的顶部执行。如果测试为真,则执行 stmt,然​​后重新初始化,循环重复。

In your case, printf("\nA") is the initialization, a (or 0) is the test, printf("\nB") is the reinitialization, and the stmt is empty.

You should have seen the A (and you did). The test should have failed on the first pass, meaning you should never have seen the stmt (but you don't know), and you should never have seen the B. This is where Turbo C++ 3.0 screwed up on the second test.

于 2012-06-18T16:20:48.513 回答
1

C(以及其他兼容的情况下)中完整的“for”循环语法是什么?

这个问题引用了标准的适用部分。除非循环至少执行一次,否则不应评估第三个表达式。所以,我想说,在第二种情况下,旧编译器打印'B'是错误的。

于 2012-06-18T16:16:27.220 回答
1

的语义for是评估第一个表达式(初始化器)然后评估第二个表达式(终止符)然后如果终止符评估为非零,则执行 for 的主体,然后评估第三个表达式(前进)并返回评估终结者。

由于您没有正文,因此该部分等于未评估任何表达式。基于此,循环应按如下方式执行:

printf("\nA");
a; // yields 0 -> terminate loop

这确实是发生的事情。

在您的第二个示例中,应该发生相同的情况(对于gcc也是如此),因为 0 评估为 0。

turbo C++ (看到 0 常量)可能会尝试执行某种循环展开优化(但未能正确执行)

于 2012-06-18T16:20:16.433 回答