void main() {
int i, j=6;
for(; i=j ; j-=2 )
printf("%d",j);
}
通过遵循常规模式,在第一个分号后应该有一个条件,但这里是初始化,所以这应该给出一个错误。 这甚至是一个有效的格式怎么样?
但输出为642
答案 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调试模式,我们可以看到:
特别注意这一点:
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