198
#include <stdio.h>

volatile int i;

int main()
{
    int c;

    for (i = 0; i < 3; i++) 
    {
         c = i &&& i;
         printf("%d\n", c);
    }

    return 0;
}

The output of the above program compiled using gcc is

0
1
1

With the -Wall or -Waddress option, gcc issues a warning:

warning: the address of ‘i’ will always evaluate as ‘true’ [-Waddress]

How is c being evaluated in the above program?

OrangeDog
  • 36,653
  • 12
  • 122
  • 207
manav m-n
  • 11,136
  • 23
  • 74
  • 97

2 Answers2

275

It's c = i && (&i);, with the second part being redundant, since &i will never evaluate to false.

For a user-defined type, where you can actually overload unary operator &, it might be different, but it's still a very bad idea.

If you turn on warnings, you'll get something like:

warning: the address of ‘i’ will always evaluate as ‘true’

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    Why not : `c = i & (&&i);`; Where `i` is some label? – anishsane Dec 20 '12 at 09:21
  • 4
    @anishsane `i` is defined as `int` and there's no labels in the question. Also, maximal munch... – Luchian Grigore Dec 20 '12 at 09:35
  • 5
    @anishsane: And the `&&` operator to take the address of a label is non-standard gcc extension anyway. But even if it were standard, the maximal munch rule would prevent it from being parsed that way (unless you insert a space). – Keith Thompson Dec 27 '12 at 20:36
  • Actually, `&i` can evaluate to `false`. Its used sometimes for defaults. Example: `void fn(type& x = *reinterpret_cast(NULL));` What is the value of `&x` in `fn` if `fn` is called without parameters? It's 0 a.k.a. false. However, using it the way described, it'll always be true unless `i == 0`, and if one was using it as I described, it would be `c = &i && i`. – Adrian May 24 '13 at 22:09
  • @Adrian you can't dereference a null pointer, which is what the `*` before `reinterpret_cast(NULL)` does. – Luchian Grigore May 24 '13 at 22:14
  • @LuchianGrigore: Although the type is dereferenced, it's not an error till the value is accessed. That's my understanding. Is it defined otherwise in the standard? – Adrian May 24 '13 at 22:17
  • @Adrian there's no value to speak of. Dereferencing a NULL pointer is undefined behavior. – Luchian Grigore May 24 '13 at 22:18
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/30599/discussion-between-adrian-and-luchian-grigore) – Adrian May 24 '13 at 22:18
  • I stand corrected. void fn(type& x = *reinterpret_cast(NULL)); is invalid. – Adrian May 24 '13 at 22:51
  • There is a misconception: UB != invalid. UB means "the language spec. don't define it", but compiler implementer can. And there are compilers that allow `int& a = *(int*)0;` and exhibit exactly that behavior (`&a == nullptr`). Of course code like that is not portable (is in fact compiler specific), but the assertion "&i is always true" is not correct: being UB, it *may* be false. No-one grants it, but it can be. – Emilio Garavaglia Jul 27 '14 at 19:26
  • @EmilioGaravaglia any statements about the behaviour of a code snippet should be assumed to have "(unless there is already UB in which case anything could happen)" implied. – M.M Jun 03 '15 at 05:38
120

There is no &&& operator or token in C. But the && (logical "and") and & (unary address-of or bitwise "and") operators do exist.

By the maximal munch rule, this:

c = i &&& i;

is equivalent to this:

c = i && & i;

It sets c to 1 if both i and &i are true, and to 0 if either of them is false.

For an int, any non-zero value is true. For a pointer, any non-null value is true (and the address of an object is always non-null). So:

It sets c to 1 if i is non-zero, or to 0 if i is equal to zero.

Which implies that the &&& is being used here just for deliberate obfuscation. The assignment might as well be any of the following:

c = i && 1;
c = !!i;
c = (bool)i;          // C++ or C with <stdbool.h>
c = i ? 1 : 0;        /* C */
c = i ? true : false; // C++
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631