if((x = 0))在C中的含义是什么?

use*_*220 29 c gcc gcc-warning

显然,在gcc/C中,编译器编译时

if ((x=0)){ some code }
Run Code Online (Sandbox Code Playgroud)

当使用时

if (x=0){ some code }
Run Code Online (Sandbox Code Playgroud)

使用,然后编译器拒绝编译.

两者有什么不同?

作为一个说明,我知道x==0和之间有什么区别x=0.我正在探索C遇到一些奇怪的代码时的行为方式.

Dav*_*ven 48

代码方面没有区别.

所发生的一切就是说,x=0而不是x==0大多数编译器在看到它时会发出警告(或错误,在你的情况下)这样的常见错误.额外的一组括号是关闭编译器的常用技巧 - 相当于说"是的,我真的打算这样做".

  • @wildplasser - 普通并不意味着同一个人每次都会这样做. (18认同)
  • @LưuVĩnhPhúc:你明确告诉你,你知道你在做什么,而`=`不是拼写错误. (10认同)
  • @wildplasser 除了 Rob 和 Hurkyl 刚才所说的之外,您还假设历史上唯一的新手程序员是十年前的您,并且现在不再存在新手程序员,将来也不会再有新手程序员了。未来。 (9认同)
  • @wildplasser:......以及任何双击“=”的专家。或者只是犯了一个简短的心理错误。 (7认同)
  • 我怀疑除了'因为他们不想要'之外没有其他好的答案,我很害怕.额外的一组括号现在无处不在,作为告诉编译器抑制它现在可能不会改变的警告的一种方式. (5认同)
  • @wildplasser如果我刚从VB.NET中的长期休假回到C,那么同一个运算符负责赋值和相等比较怎么办?我的手指会被用来键入一个`=`,当我再次在C中编码时,我可能会自动这样做.你可能是万无一失的,但不是每个人都是. (5认同)

Pav*_*rda 36

两者在语法上都是正确的C,编译器必须处理它.但是,编译器可能会根据配置发出警告甚至错误(例如gcc中的-Werror),因为其中一个是如此可疑,以至于您永远不会想到它是故意的.当你使用类似的东西时if (x = 0) { ... }(x如果零非零则分配零并运行块),你几乎总是实际意味着if (x == 0) { ... }(如果x为零则运行块).

现在让我们了解为什么if ((x = 0)) { ... }不被认为足够可疑以保证相同类型的警告(这个特殊的代码仍然是可疑的,因为条件总是评估为零,并且身体永远不会运行)...

某些C开发人员使用了一个习惯用法(我就是其中之一),你将一个赋值括在括号中并利用这个特性,即使赋值本身也有一个值,它就是赋值.

例:

#include <stdio.h>

int main(int argc, char **argv)
{
    int c;

    while ((c = getchar()) != '\n')
            printf("Character: '%c' (0x%02x)\n", c, c);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

测试示例:

$ ./test
Hello!
Character: 'H' (0x48)
Character: 'e' (0x65)
Character: 'l' (0x6c)
Character: 'l' (0x6c)
Character: 'o' (0x6f)
Character: '!' (0x21)
Run Code Online (Sandbox Code Playgroud)

最重要的部分是条件(c = getchar()) != '\n',你第一次分配的结果getchar()c,然后检查是否有特定的值.在这种情况下,我们从标准输入中逐个读取字符,直到读取一行(技术上直到我们读取一个\n字符).这样做的主要优点是它允许你getchar()填入测试.否则你将不得不使用逗号表示法,带有中断的无限循环,或者在循环之前和循环结束时将它放在一起.

有时候,你比较非零值,比如\n,-1和类似的,但有时你比较为零或者,当指针时,对NULL.让我们找一个例子NULL,这在内存分配中很常见.

char *p;

if ((p = malloc(50)) == NULL) {
    ...handle error...
}
Run Code Online (Sandbox Code Playgroud)

当然你可以把它写成:

char *p;

p = malloc(50);
if (p == NULL) {
    ...handle error...
}
Run Code Online (Sandbox Code Playgroud)

但根据您的口味,您还可以使用:

char *p;

if (!(p = malloc(50))) {
    ...handle error...
}
Run Code Online (Sandbox Code Playgroud)

或者甚至将它转向另一个方向(顺便说一下,我总是首先处理错误情况):

char *p;

if ((p = malloc(50))) {
    ...do stuff...
} else {
    ...handle error...
}
Run Code Online (Sandbox Code Playgroud)

在最后一种情况下,条件(p = malloc(50))完全等同于p = malloc(50)但后者是高度可疑的,因为已经提到的在C和派生语言中执行赋值而不是比较的常见错误.请注意,这不仅涉及可疑编译器,还涉及人们阅读代码并查看潜在错误.

冗余括号只是一种告诉读者和编译器的方法,这种分配绝对是有意的,并且不是那种常见错误的发生.

  • 符合*C编译器的*不能拒绝`if(x = 0)`或`if((x = 0))`.它可能会警告任何它喜欢的东西,包括你穿的那件衬衫. (8认同)
  • @PavelŠimerda:阅读评论"标准将允许编译器警告任何它喜欢的东西 - 即使C编译器不应该理解的事情 - 只要警告不会阻止编译一致的程序".请注意,`-Werror`选项要求编译器以与标准相反的方式运行,但对于许多程序员来说更有用. (6认同)
  • @PavelŠimerda:不,我正在提出一个重要且有效的观点(注入幽默). (4认同)
  • 任何有价值的编辑都应警告夏威夷衬衫. (3认同)
  • @PavelŠimerda:重点是编译器可以警告任何他们喜欢的东西. (2认同)

小智 19

除非你有,否则代码不应该"拒绝"编译-Werror.如果您启用了警告,它可能会告诉您:

警告:建议用作真值的赋值括号[-Whatarentheses] while (*dest++ = *src++)

具体来说,海湾合作委员会的文件说明了这个警告的目的:

如果在某些上下文中省略括号,则会发出警告,例如在预期真值的上下文中存在赋值,或者当嵌套运算符时,优先级通常会让人感到困惑.