如果(x=0)在C中是什么意思?

时间:2022-07-10 22:26:25

So apparently, in gcc/C, a compiler compiles when

显然,在gcc/C中,编译器是在什么时候编译的

if ((x=0)){ some code }

is used, while when

使用,什么时候

if (x=0){ some code }

is used, then compiler refuses to compile.

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

What are the differences between two?

两者的区别是什么?

As a note, I know what is the difference between x==0 and x=0. I am just exploring how C behaves when met with some weird codes.

注意,我知道x=0和x=0的差是多少。我只是在探索当遇到一些奇怪的代码时C的行为。

3 个解决方案

#1


48  

There is no difference, code-wise.

代码上没有区别。

All that's happening is that saying x=0 instead of x==0 is such a common mistake that most compilers will emit a warning (or error, in your case) when they see it. The extra set of parentheses is a common trick to shut the compiler up --- the equivalent of saying 'yes, I really meant to do this'.

所发生的是,说x=0而不是x=0是一个常见的错误,大多数编译器在看到它时都会发出警告(在您的例子中是错误)。额外的一组括号是关闭编译器的常见技巧——相当于说“是的,我真的想这么做”。

#2


36  

Both are syntactically correct C and the compiler has to cope with it. But the compiler may, depending on the configuration, issue a warning or even error (e.g. -Werror in gcc) because one of them is so suspicious that you would never expect it to be intentional. When you use something like if (x = 0) { ... } (assign zero to x and run the block if zero is non-zero), you almost always actually mean if (x == 0) { ... } (run the block if x is zero).

两者都是语法正确的C,编译器必须处理它。但是编译器可能会根据配置发出警告甚至错误(例如,gcc中的-Werror),因为其中一个非常可疑,您永远不会期望它是故意的。当你使用if (x = 0){…}(将0赋给x,如果0是非0则运行块),实际上几乎总是指if (x = 0){…}(如果x为0,运行block)。

Now let's get to why if ((x = 0)) { ... } is not considered suspicious enough to warrant the same type of warning (this particular code is still suspicious because the condition always evaluates to zero and the body is never run)...

现在我们来看看为什么if (x = 0){…}被认为不够可疑,不足以保证相同类型的警告(此特定代码仍然可疑,因为条件总是计算为零,并且主体永远不会运行)……

There's an idiom used by some C developers (I'm one of them) where you put an assignment into parentheses and make use of the feature that even the assignment has a value itself and it's the assigned value.

有些C开发人员(我就是其中之一)使用了这样一个习惯用法:将赋值放在括号中,并利用赋值本身就具有值的特性,即赋值本身就是赋值。

Example:

例子:

#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 the example:

测试的例子:

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

The important part was the condition (c = getchar()) != '\n' where you first assign the result of getchar() to c and then check it for a specific value. In this very case we are reading characters one by one from the standard input until the and of a line (technically until we read a \n character). The main advantage of doing it this way is that it allows you to stuff the getchar() into the test. You would otherwise have to use the comma notation, an infinite loop with a break, or put it both before the loop and at the end of the loop.

重要的部分是条件(c = getchar()) != '\n',在这里您首先将getchar()的结果赋给c,然后检查它的特定值。在本例中,我们从标准输入中逐个读取字符,直到行(技术上说,直到读取一个\n字符)。这样做的主要好处是,它允许您将getchar()填充到测试中。否则,您将不得不使用逗号表示法,一个带有中断的无限循环,或者将它放在循环的前面和循环的末尾。

Sometimes you compare to non-zero values, like \n, -1 and similar, but sometimes you compare to zero or, when working with pointers, to NULL. Let's find an example for NULL, which is pretty common with memory allocation.

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

char *p;

if ((p = malloc(50)) == NULL) {
    ...handle error...
}

Of course you could write it as:

当然可以这样写:

char *p;

p = malloc(50);
if (p == NULL) {
    ...handle error...
}

But depending on your taste you could also use:

但是根据你的口味,你也可以使用:

char *p;

if (!(p = malloc(50))) {
    ...handle error...
}

Or even turn it the other way round (which btw goes against my preference of always handling the error case first):

或者甚至反过来(顺便说一句,这与我总是先处理错误案例的偏好背道而驰):

char *p;

if ((p = malloc(50))) {
    ...do stuff...
} else {
    ...handle error...
}

In the last case, the condition is (p = malloc(50)) which is exactly equivalent to p = malloc(50) but the latter is highly suspicious because of the already mentioned common mistake of performing assignment instead of comparison in C and derived languages. Note that this is not only about suspicious compilers but also humans reading the code and looking at the potential error.

在最后一种情况下,条件为(p = malloc(50)),这与p = malloc(50)完全相同,但后者非常可疑,因为前面已经提到了在C和派生语言中执行赋值而不是比较的常见错误。注意,这不仅与可疑的编译器有关,而且还与读取代码并查看潜在错误有关。

The redundant parentheses are simply a means to tell the readers and the compiler that this assignment is definitely intentional and that it's not an occurence of that common bug.

冗余括号只是一种方法,用来告诉读者和编译器这个赋值肯定是有意的,它不是那个常见bug的出现。

#3


19  

The code shouldn't "refuse" to compile unless you have -Werror. If you have warnings enabled, it might tell you:

代码不应该“拒绝”编译,除非您有-Werror。如果启用了警告,它可能会告诉您:

warning: suggest parentheses around assignment used as truth value [-Wparentheses] while (*dest++ = *src++)

警告:建议在赋值时使用圆括号作为真值[- w括号],而(*dest++ + = *src++ ++)

Specifically, the GCC docs say this about the purpose of the warning:

具体来说,GCC的文档说明了警告的目的:

Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about.

如果在某些上下文中省略了括号,比如在需要真值的上下文中有赋值,或者在嵌套操作符(其优先级常常让人感到困惑)时,要发出警告。

#1


48  

There is no difference, code-wise.

代码上没有区别。

All that's happening is that saying x=0 instead of x==0 is such a common mistake that most compilers will emit a warning (or error, in your case) when they see it. The extra set of parentheses is a common trick to shut the compiler up --- the equivalent of saying 'yes, I really meant to do this'.

所发生的是,说x=0而不是x=0是一个常见的错误,大多数编译器在看到它时都会发出警告(在您的例子中是错误)。额外的一组括号是关闭编译器的常见技巧——相当于说“是的,我真的想这么做”。

#2


36  

Both are syntactically correct C and the compiler has to cope with it. But the compiler may, depending on the configuration, issue a warning or even error (e.g. -Werror in gcc) because one of them is so suspicious that you would never expect it to be intentional. When you use something like if (x = 0) { ... } (assign zero to x and run the block if zero is non-zero), you almost always actually mean if (x == 0) { ... } (run the block if x is zero).

两者都是语法正确的C,编译器必须处理它。但是编译器可能会根据配置发出警告甚至错误(例如,gcc中的-Werror),因为其中一个非常可疑,您永远不会期望它是故意的。当你使用if (x = 0){…}(将0赋给x,如果0是非0则运行块),实际上几乎总是指if (x = 0){…}(如果x为0,运行block)。

Now let's get to why if ((x = 0)) { ... } is not considered suspicious enough to warrant the same type of warning (this particular code is still suspicious because the condition always evaluates to zero and the body is never run)...

现在我们来看看为什么if (x = 0){…}被认为不够可疑,不足以保证相同类型的警告(此特定代码仍然可疑,因为条件总是计算为零,并且主体永远不会运行)……

There's an idiom used by some C developers (I'm one of them) where you put an assignment into parentheses and make use of the feature that even the assignment has a value itself and it's the assigned value.

有些C开发人员(我就是其中之一)使用了这样一个习惯用法:将赋值放在括号中,并利用赋值本身就具有值的特性,即赋值本身就是赋值。

Example:

例子:

#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 the example:

测试的例子:

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

The important part was the condition (c = getchar()) != '\n' where you first assign the result of getchar() to c and then check it for a specific value. In this very case we are reading characters one by one from the standard input until the and of a line (technically until we read a \n character). The main advantage of doing it this way is that it allows you to stuff the getchar() into the test. You would otherwise have to use the comma notation, an infinite loop with a break, or put it both before the loop and at the end of the loop.

重要的部分是条件(c = getchar()) != '\n',在这里您首先将getchar()的结果赋给c,然后检查它的特定值。在本例中,我们从标准输入中逐个读取字符,直到行(技术上说,直到读取一个\n字符)。这样做的主要好处是,它允许您将getchar()填充到测试中。否则,您将不得不使用逗号表示法,一个带有中断的无限循环,或者将它放在循环的前面和循环的末尾。

Sometimes you compare to non-zero values, like \n, -1 and similar, but sometimes you compare to zero or, when working with pointers, to NULL. Let's find an example for NULL, which is pretty common with memory allocation.

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

char *p;

if ((p = malloc(50)) == NULL) {
    ...handle error...
}

Of course you could write it as:

当然可以这样写:

char *p;

p = malloc(50);
if (p == NULL) {
    ...handle error...
}

But depending on your taste you could also use:

但是根据你的口味,你也可以使用:

char *p;

if (!(p = malloc(50))) {
    ...handle error...
}

Or even turn it the other way round (which btw goes against my preference of always handling the error case first):

或者甚至反过来(顺便说一句,这与我总是先处理错误案例的偏好背道而驰):

char *p;

if ((p = malloc(50))) {
    ...do stuff...
} else {
    ...handle error...
}

In the last case, the condition is (p = malloc(50)) which is exactly equivalent to p = malloc(50) but the latter is highly suspicious because of the already mentioned common mistake of performing assignment instead of comparison in C and derived languages. Note that this is not only about suspicious compilers but also humans reading the code and looking at the potential error.

在最后一种情况下,条件为(p = malloc(50)),这与p = malloc(50)完全相同,但后者非常可疑,因为前面已经提到了在C和派生语言中执行赋值而不是比较的常见错误。注意,这不仅与可疑的编译器有关,而且还与读取代码并查看潜在错误有关。

The redundant parentheses are simply a means to tell the readers and the compiler that this assignment is definitely intentional and that it's not an occurence of that common bug.

冗余括号只是一种方法,用来告诉读者和编译器这个赋值肯定是有意的,它不是那个常见bug的出现。

#3


19  

The code shouldn't "refuse" to compile unless you have -Werror. If you have warnings enabled, it might tell you:

代码不应该“拒绝”编译,除非您有-Werror。如果启用了警告,它可能会告诉您:

warning: suggest parentheses around assignment used as truth value [-Wparentheses] while (*dest++ = *src++)

警告:建议在赋值时使用圆括号作为真值[- w括号],而(*dest++ + = *src++ ++)

Specifically, the GCC docs say this about the purpose of the warning:

具体来说,GCC的文档说明了警告的目的:

Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected, or when operators are nested whose precedence people often get confused about.

如果在某些上下文中省略了括号,比如在需要真值的上下文中有赋值,或者在嵌套操作符(其优先级常常让人感到困惑)时,要发出警告。