请考虑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公司的采访中被问到这个问题,当他没有给出答案时,面试官给出了这个解释。但我发现这是愚蠢的。你如何要求某人使用“bug”,好像它是语言提供的“设施”?因为它被称为“设施”和“技术”,无论我们在第二个表达式中传递0作为文字还是在值为0的变量中传递,结果应该是相同的。
我错误地认为面试官非常愚蠢地提出这样的问题并且表明他的无能?
答案 0 :(得分:12)
第二个例子的TCC输出错误。
来自C99标准:
声明
for( clause-1 ; expression-2 ; 表达式3 ) 声明
表现如下:表达式 expression-2 是控制 在每次执行循环体之前计算的表达式。 表达式表达式-3 在之后被评估为空表达式 循环体的每次执行。 [...]
显然,这里没有迭代,所以永远不应该执行 expression-3 。
同样,在C90标准中(或至少在draft that I found中),它表示:
除了循环体中的continue语句的行为, 声明
for ( expression-1 ; expression-2 ; expression-3 ) statement
和陈述序列
expression-1 ; while ( expression-2) { statement expression-3 ; }
是等价的。
答案 1 :(得分:3)
Turbo C ++ 3.0于1990年代发布,很快就发布了3.1版本。
我猜你的古代编译器里面有很多bug,它们很快就更新了。此外,它可能不有这样的错误,但可能已经发出优化的组件,在新的管道衬砌架构下失败。
无论如何,保证在您当前的平台上不支持 。当谈到一个不受支持的编译器,因为该平台是在将近20年后创建的,所以你不能因为发出错误的程序而对它进行错误的判断。
答案 2 :(得分:2)
gcc输出正确。
第一种情况下的Turbo C ++ 3.0输出是正确的。
第二种情况下的TurboC ++ 3.0输出是错误的。
在Turbo C ++ 3.0编译器中,您似乎找到了一个边缘情况,导致代码生成错误。
C或C ++中的for-stmt具有通用语法
for(initialization; test; reinitialization)stmt
在循环开始之前执行初始化一次。测试在循环的TOP处进行。如果测试为真,则执行stmt,然后重新初始化,循环重复。
在你的情况下,printf(" \ nA")是初始化,a(或0)是测试,printf(" \ nB")是重新初始化,并且stmt是空的。
你应该看过A(你做过)。测试应该在第一次通过时失败,这意味着你永远不应该看到stmt(但你不知道),你应该永远不会看到B.这是Turbo C ++ 3.0搞砸第二次测试的地方
答案 3 :(得分:1)
What is the full "for" loop syntax in C (and others in case they are compatible)?
此问题引用了该标准的适用部分。除非循环至少执行一次,否则不应评估第3个表达式。所以,我会说在第二种情况下,旧编译器打印'B'是错误的。
答案 4 :(得分:1)
for
的语义是第一个表达式被计算(初始化)然后第二个表达式被计算(终止符)然后如果终止符被计算为非零,则执行for的主体,然后是第三个评估表达式(进展)并返回评估终止子。
由于您没有正文,因此该部分无法评估任何表达式。基于此,循环应按如下方式执行:
printf("\nA");
a; // yields 0 -> terminate loop
确实会发生这种情况。
在你的第二个例子中,同样的事情应该发生(就像 gcc 一样),因为0评估为0。
有可能 turbo C ++ - 看到0常量 - 尝试执行某种循环展开优化(并且未能正确执行)