2

I review the coreutils's source tree then i found the code below which confuse me a little. (at coreutils-8.23/lib/getopt.c line 237)

d->__posixly_correct = posixly_correct || !!getenv ("POSIXLY_CORRECT");

the using of '!' was reversing the logical state of its operand, if A was true, the !A was false, so !!A true again. I don't understand the intention of the author.

3 Answers3

4

This is generally done to force the return into either a 1 or a 0.

If something returns either 0 or NULL, then the final state of !!<expression> will be 0 and thereby false .

If something returns anything other than 0 or NULL, then the final state will be 1 and thereby true

Further reference here.

Davy M
  • 1,697
  • 4
  • 20
  • 27
3

As others have pointed out, the purpose is to guarantee that the truthy value is 1 instead of all possible nonzero values.

This can prevent bugs where people rely on true being 1, leading to bugs like:

env = getenv("POSIXLY_CORRECT")
if (env == true) {
    // handle the true case
}

Engineers would use !! as a defense against bad coders. Yes, it is better to not write buggy code, but it's almost as good to ensure that the bugs never bit you.

Note that comparing a boolean to true is still Bad Coding (tm), even if you are using the !! trick. There is no reason for any test beyond if (bool_var). And the example given is suboptimal as well, as it relies on NULL being 0, which might not be the case on all architectures. The code you give really ought to be

d->__posixly_correct = posixly_correct || getenv("POSIXLY_CORRECT") != NULL;

to defend against the case where 0 is a legitimate memory address and happens to be where the getenv()'s return is stored

One Guy Hacking
  • 1,176
  • 11
  • 16
2

You'll see this sometimes when using non bool as a bit mask.

Any non-zero value is truthy. Negating a nonzero value produces 0, which is falsy. Negating that again, always produces 1, which is truthy. Note, that this final result can differ from the the input (which can be any other truthy value).

Basically it maps values from (true: 1-255, false: 0) to (true: 1, false: 0)

Alexander
  • 59,041
  • 12
  • 98
  • 151