显然,在gcc / C中,编译器在
时编译if ((x=0)){ some code }
时使用
if (x=0){ some code }
使用,然后编译器拒绝编译。
两者之间有什么区别?
作为备注,我知道x==0
和x=0
之间的区别。我正在探索C遇到一些奇怪的代码时的行为。
答案 0 :(得分:48)
代码方面没有区别。
所有发生的事情都是说x=0
而不是x==0
是一个常见的错误,大多数编译器会在看到它时发出警告(或错误,在你的情况下)。额外的一组括号是关闭编译器的常用技巧 - 相当于说'是的,我真的打算这样做'。
答案 1 :(得分:36)
两者在语法上都是正确的C,编译器必须处理它。但是,编译器可能会根据配置发出警告甚至错误(例如gcc中的-Werror),因为其中一个是如此可疑,以至于你永远不会想到它是故意的。当您使用if (x = 0) { ... }
之类的内容时(将{0}赋值为0并运行该块,如果零为非零),您几乎总是实际意味着x
(如果if (x == 0) { ... }
则运行该块}是零)。
现在让我们了解为什么x
不被认为可疑
相同类型的警告(这个特殊的代码仍然是可疑的,因为条件总是评估为零而且正文永远不会运行)...
有些C开发人员使用了一个习惯用法(我就是其中之一),你将一个赋值括在括号中并利用这个特征,即使赋值本身也有一个值,它就是赋值。
示例:
if ((x = 0)) { ... }
测试示例:
#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;
}
重要的部分是条件$ ./test
Hello!
Character: 'H' (0x48)
Character: 'e' (0x65)
Character: 'l' (0x6c)
Character: 'l' (0x6c)
Character: 'o' (0x6f)
Character: '!' (0x21)
,您首先将(c = getchar()) != '\n'
的结果分配给getchar()
,然后检查它是否为特定值。在这种情况下,我们从标准输入中逐个读取字符,直到读取一行(技术上直到我们读取c
字符)。这样做的主要优点是它允许您将\n
填入测试。否则你将不得不使用逗号表示法,一个带有中断的无限循环,或者在循环之前和循环结束时都将它放在一起。
有时您会与非零值进行比较,例如getchar()
,\n
和类似值,但有时您会比较为零,或者在使用指针时,会与-1
进行比较。让我们找一个NULL
的例子,这在内存分配方面很常见。
NULL
当然你可以把它写成:
char *p;
if ((p = malloc(50)) == NULL) {
...handle error...
}
但根据您的口味,您也可以使用:
char *p;
p = malloc(50);
if (p == NULL) {
...handle error...
}
或者甚至反过来转向它(顺便说一下,我的偏好总是首先处理错误案例):
char *p;
if (!(p = malloc(50))) {
...handle error...
}
在最后一种情况下,条件是char *p;
if ((p = malloc(50))) {
...do stuff...
} else {
...handle error...
}
,它与(p = malloc(50))
完全相同,但后者非常可疑,因为已经提到的常见错误执行了赋值C语言和派生语言的比较请注意,这不仅涉及可疑编译器,还涉及人们阅读代码并查看潜在错误。
冗余括号只是一种告诉读者和编译器的方法,这种分配绝对是有意的,而且不是常见错误的发生。
答案 2 :(得分:19)
除非你有-Werror
,否则代码不应该“拒绝”编译。如果您启用了警告,它可能会告诉您:
警告:建议用作真值的赋值括号[-Whatarentheses]
while (*dest++ = *src++)
具体来说,GCC docs对警告的目的说了这个:
如果在某些上下文中省略括号,请发出警告,例如何时 在预期真值的上下文中有一个赋值, 或者当运算符嵌套时,人们经常会得到优先级 困惑。