为什么这段代码不会出错?

时间:2016-11-03 06:32:32

标签: c for-loop syntax

void main() {
    int i, j=6;
    for(; i=j ; j-=2 )
        printf("%d",j);
}

通过遵循常规模式,在第一个分号后应该有一个条件,但这里是初始化,所以这应该给出一个错误。 这甚至是一个有效的格式怎么样?

但输出为642

4 个答案:

答案 0 :(得分:3)

i=j也是一个表达式,其值是赋值后i的值。所以它可以作为一个条件。

您通常会看到这种类型的聪明使用:

if ((ptr = some_complex_function()) != NULL)
{
  /* Use ptr */
}

一些程序员喜欢折叠作业并检查一行代码。这对于可读性有多好或多坏是一个观点问题。

答案 1 :(得分:3)

首先,让我更正术语,i=j 作业 ,而不是初始化。

那就是说,让我们先分析for循环语法。

  

for ( 第1条;表达式-2;表达式3 ) 声明

因此,表达式-2 应该是一个“表达式”。

现在,来到具有赋值运算符

的语句的语法
  

赋值表达式:
条件表达式
一元表达式   assignment-operator assignment-expression

因此,正如规范C11在章节§6.5.16中提到的那样,赋值操作也是表达式,非常适合表达式-2 参与for循环语法。

关于结果

  

这是   赋值表达式具有赋值后左操作数的值,

因此,i=j基本上会将j的值分配给i,然后i的值将用于条件检查(即非零或零为TRUE或FALSE)。

TL; DR 从语法上讲,代码没有问题,因此编译器不会生成错误。

此外,对于托管环境,void main()int main(void)符合标准。

答案 2 :(得分:1)

您的代码不包含语法错误,因此编译器接受它并生成代码以生成642

条件i=j被解释为(i = j) != 0

要防止出现这种情况和许多类似的错误模式,请启用更多编译器警告,并使用以下命令使其致命:

gcc -Wall -W -Werror

如果您使用clang,请使用clang -Weverything -Werror

答案 3 :(得分:1)

这是一个非常好的问题。

要真正理解这一点,您最好知道如何在计算机中执行C代码: 首先,编译器将C代码编译成汇编代码,然后汇编代码将被转换为机器代码,可直接在主存中运行。

至于你的代码:

void main() {
    int i, j=6;
    for(; i=j ; j-=2 )
        printf("%d",j);
}

要弄清楚结果为642的原因,我们希望看到它的汇编代码。

使用VS调试模式,我们可以看到:

enter image description here

特别注意这一点:

010217D0  mov         eax,dword ptr [j]  
010217D3  mov         dword ptr [i],eax  
010217D6  cmp         dword ptr [i],0  
010217DA  je          main+4Fh (010217EFh)  

四行汇编代码对应C代码" i = j",表示首先将j的值移动到寄存器eax,然后将寄存器eax的值移到i(从计算机开始)不能直接将j的值移动到i,它只使用寄存器eax作为桥接器,然后将i的值与0进行比较,如果它们相等,则跳转到010217EFh,循环结束;如果没有,循环继续。

所以实际上它首先是一个赋值,然后是一个比较来决定循环是否结束;当6下降到0时,循环终于停止了,我希望这可以帮助你理解为什么结果是642:D