29

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

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.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
user56220
  • 327
  • 1
  • 3
  • 6
  • 3
    And I can't see why anyone would want to do `if ((x=0)) {...}` since that condition will always be false. (Or `x=N` for any constant `N`.) If this is in code you came across in the wild, maybe someone was trying to suppress the warning without understanding what the warning was for. – fluffy Sep 21 '14 at 17:10
  • 3
    By the way, an easy trick to help detect many cases where = was used in place of == is to always put the constant on the left -- 'if(0=x)' will produce a can't-assign-to-constant error. – keshlam Sep 21 '14 at 18:04
  • 3
    @keshlam Also known as [Yoda conditions](https://en.wikipedia.org/wiki/Yoda_conditions). – Palec Sep 21 '14 at 18:05
  • 1
    There was a famous attempt to insert a backdoor into the Linux kernel once using code like this: https://freedom-to-tinker.com/blog/felten/the-linux-backdoor-attempt-of-2003/ – Alex MDC Sep 22 '14 at 04:08
  • 4
    Also known as making your code less readable because you're afraid you don't know how to type. :) – cHao Sep 22 '14 at 04:09
  • 4
    Which version of GCC and with which switches? With `-Wall`, Red Hat 4.8.3-1 suggests *parentheses around assignment used as truth value*, but it compiles just fine... – Dennis Sep 22 '14 at 04:25
  • See [Compiler warning - suggest parentheses around assignment used as truth value](http://stackoverflow.com/questions/5476759/compiler-warning-suggest-parentheses-around-assignment-used-as-truth-value) – Qantas 94 Heavy Sep 22 '14 at 08:30
  • The compiler interprets the extra pair of parentheses as an "OK, you _really_ mean `=`, not `==`". – Lutz Prechelt Sep 22 '14 at 15:28
  • Did you really *read* what the compiler tells you when it's complaining? – harper Sep 28 '14 at 15:04

3 Answers3

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'.

David Given
  • 13,277
  • 9
  • 76
  • 123
  • Why doesn't the compiler warn when putting inside the bracket? – phuclv Sep 21 '14 at 15:29
  • 5
    I suspect there's no good answer other than 'because they didn't want it to', I'm afraid. The extra set of parentheses is now so ubiquitous as a way of telling the compiler to suppress the warning that it's probably not going to change now. – David Given Sep 21 '14 at 15:33
  • 10
    @LưuVĩnhPhúc: You're telling explicitly that you know what you're doing and the `=` isn't a typo. – Jack Sep 21 '14 at 16:49
  • `... is such a common mistake ..` It is not. It was ten years ago when I last made this misstake. – wildplasser Sep 21 '14 at 22:33
  • 18
    @wildplasser -- common doesn't mean the same person makes it every time. – Rob Starling Sep 21 '14 at 22:35
  • On the flip side, if you want to force your compiler to give an error, change the if statement around: if (0=x) This will complain, because you cannot set the value of a constant. – Sarima Sep 21 '14 at 22:37
  • It is only made by novices. After a few months it will be very rare. – wildplasser Sep 21 '14 at 22:38
  • 7
    @wildplasser: ... as well as any expert who flubs up double-tapping `=`. Or simply makes a brief mental error. –  Sep 22 '14 at 00:30
  • 9
    @wildplasser In addition to what Rob and Hurkyl just said, you're making the assumption that the only novice programmer in history was you, ten years ago, and that there are no more novice programmers in existence now nor will there ever be in the future. – Lily Chung Sep 22 '14 at 00:44
  • 5
    @wildplasser What if I've just returned to C from a long sabbatical in VB.NET, where the same operator is responsible for both assignment and equality comparison? My fingers will be so used to typing a single `=` that I'll likely do so automatically when coding in C again. You might be infallible, but not everyone is. – Will Vousden Sep 22 '14 at 09:05
  • 1
    @wildplasser Or any number of other non-C-style languages. My language of choice uses `:` for assignment and `=` for equality comparison, so single-equals in an "if" statement is a common sight for me that doesn't always register as an error when I use C. – Izkata Sep 22 '14 at 13:58
  • I'm certainly not infallable: I make a lot of logic errors, fencepost errors, I increment the wrong pointers or indexes, but the `=` vs `==` error just does not happen much. And if it would happen, I'll have to be fix just like the others. But its relative frequency of occurance still does not justify a defensive style of programming, IMHO. – wildplasser Sep 22 '14 at 21:54
  • @Izkata Out of curiosity, what language is that? I've never seen one that used `:` for assignment, and I'm a programming language junkie. (Unless it was a tyop for `:=`.) – David Given Sep 23 '14 at 22:22
  • @DavidGiven [Rebol](http://en.wikipedia.org/wiki/Rebol), and not a typo (although it is a simplification - it's actually a different datatype: in `foo: "bar"`, `foo:` is a `set-word!` while `foo` (to use the value) is a `word!`) – Izkata Sep 23 '14 at 22:48
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).

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)...

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.

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.

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.

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.

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.

Pavel Šimerda
  • 5,783
  • 1
  • 31
  • 31
  • "assing zero to x and run the block if zero is zero" ... What? Should that be "if zero is true"? (Which is always false, BTW) – leonbloy Sep 21 '14 at 19:44
  • Thanks, edited. I originally considered saying that block will be never run but that's a consequence, not the meaning of the code. – Pavel Šimerda Sep 21 '14 at 19:50
  • 8
    A *conforming* C compiler may not reject either `if (x = 0)` or `if ((x = 0))`. It may warn about anything it likes, including that shirt you're wearing. – Keith Thompson Sep 21 '14 at 20:07
  • @KeithThompson: That [about the shirt] is not a very useful information, though, is it? It would be nice if you were more explicit about the purpose of your comment. – Pavel Šimerda Sep 21 '14 at 20:17
  • 2
    @PavelŠimerda: The point is that compilers can warn about anything they like. – Keith Thompson Sep 21 '14 at 20:33
  • @KeithThompson: Obviously. And the value of those comments to readers of the answer? Wouldn't we do better if we just deleted them? – Pavel Šimerda Sep 21 '14 at 20:42
  • 4
    @PavelŠimerda: No, I was making an important and valid point (with a small injection of humor). – Keith Thompson Sep 21 '14 at 21:21
  • 6
    @PavelŠimerda: Read the comment as "the standard would allow the the compiler to warn about anything it likes--even things a C compiler shouldn't sensibly care about--provided only that the warnings don't prevent compilation of a conforming program". Note that the `-Werror` option requests the compiler to behave in a fashion which is contrary to the standard, but is for many programmers more useful. – supercat Sep 21 '14 at 21:56
  • Just so it's said...if someone *meant* to say `if (p == malloc(50))`, then they should stick with Java. Or some other hand-holding language that doesn't leak memory every time you do that. – cHao Sep 22 '14 at 04:34
  • @supercat: Did you just want to state the obvious or you want it somehow incorporate into the answer? – Pavel Šimerda Sep 22 '14 at 07:54
  • Just to interject on the subject of the shirt; it's not just hyperbole. I've had a compiler warn me about a particularly offensive Hawaiian shirt before. – mirichan Sep 22 '14 at 09:15
  • 3
    Any compiler worth its salt should warn about Hawaiian shirts. – Martijn Sep 22 '14 at 10:46
19

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

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

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

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.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130