57

I have encountered the following snippet:

pt->aa[!!(ts->flags & MASK)] = -val;
  1. What does !! (double exclamation marks/ exclamation points/ two NOT operators) stand for in c?
  2. Doesn't (!!NULL) == NULL?
0x90
  • 39,472
  • 36
  • 165
  • 245
  • 3
    Related: http://stackoverflow.com/questions/10307281/c-operator-is-a-two-not – user000001 Feb 07 '13 at 14:15
  • 1
    example: In my code "[**Decimal to Binary: Size independent: First Method**](http://stackoverflow.com/questions/14104208/convert-integer-to-binary-and-store-it-in-an-integer-array-of-specified-sizec/14314522#14314522)" I have used `!!` to convert a `int` into `0` or `1` bit – Grijesh Chauhan Feb 07 '13 at 14:42
  • 3
    Also please note that this code is bad. Problem 1: using a bool as array index. Problem 2: the weird !! syntax, which only confuses the reader (as we can tell from this question). Problem 3: calculating array index with a needless complex expression, it should have been moved to a line of its own. All of these things point to the same thing: I suspect that we have a programmer who think they are terribly smart, but in reality have much to learn about proper program design and code maintenance. – Lundin Feb 07 '13 at 15:24
  • 5
    Speaking of the _possible duplicate_ nomination, keep in mind that C and C++ are two _different_ languages. As a result I believe it is reasonable to have two independent questions with independent answers. Even if semantics are similar today, future standards may change this state. – Jan Feb 07 '13 at 15:45
  • Jan is correct, the answer to the linked duplicate is not correct for C. – Jack Aidley Feb 07 '13 at 16:17
  • @Jan, this question is tagged as [tag:c], and the related question is tagged as [tag:c]. if the tags are incorrect, they should be updated. – zzzzBov Feb 07 '13 at 22:02
  • @JackAidley, if the accepted answer is not correct, then someone looking for an answer should place a bounty on the existing question, not ask a duplicate. – zzzzBov Feb 07 '13 at 22:03
  • @zzzzBov: both answers are correct. They are not duplicates. C and C++ handle this differently, the duplicate pointed to a correctly answered C++ question; this is a correctly answered C question. And, now, I see the question is correctly not marked as a duplicate. All is good in the hood. – Jack Aidley Feb 07 '13 at 22:40
  • @zzzzBov: Actually I see this has been marked as a duplicate of more than one; the one it is _now_ suggested as a duplicate of, is a c question - also answered correctly - it had been tagged as a duplicate of a question asking the same thing for C++. Confusion reigns! – Jack Aidley Feb 07 '13 at 22:42
  • Mind you, Jan's answer is better than the one to http://stackoverflow.com/questions/10307281/c-operator-is-a-two-not – Jack Aidley Feb 07 '13 at 22:43

7 Answers7

89

! is negation. So !! is negation of negation. What is important is the fact that the result will be an int.

  • !!x if x == 0 is !!0, that is !1, that is 0.
  • !!x if x != 0 is !!(!0), that is !!1, that is !0, that is 1.

!! is used commonly if you want to convert any non-zero value to 1 while being certain that 0 remains a 0.

And indeed, !!NULL == NULL, since !!NULL == !!0 and !!0 == !1 and finally !1 == 0.

Consequently, in the short piece of code you cited the array subscript will be either 0 if the value of the expression in parenthesis is NULL, and 1 otherwise.

tjati
  • 5,761
  • 4
  • 41
  • 56
Jan
  • 11,636
  • 38
  • 47
  • 2
    The resulting value is either `0` or `1` of type `int`. – pmg Feb 07 '13 at 13:16
  • 9
    `(!!NULL) == NULL` is true if `NULL` is `0`. If `NULL` is, say, `((void*)0)`, you might get a pointer-to-integer comparison warning. The whole point of using `!!` is to convert from "truey" and "falsy" expression results to integers. – Mike DeSimone Feb 07 '13 at 13:25
  • @MikeDeSimone, @pmg, thanks, I've added information about the value of the expression being an `int`. – Jan Feb 07 '13 at 13:30
  • 1
    !!NULL should never be a warning regardless of the type of NULL. !ptr is normal usage. – R.. GitHub STOP HELPING ICE Feb 07 '13 at 15:01
  • 3
    @SandyLee: Not quite. `!!false` is `0`, and `!!true` is `1`. – Justin ᚅᚔᚈᚄᚒᚔ Feb 07 '13 at 16:52
  • I have heard `!!` referred to as the _normalise_ operator. – David Given Jan 26 '15 at 23:05
  • @ShuklaSannidhya Also, note that while `!!0` is `0` and `!!1` is `1`, `!!2` is also `1`, as is `!!3`, `!!4`, `!!5`... etc. It'll convert any value to a 0 or a 1. – David Given Jan 26 '15 at 23:07
  • 2
    The bit about NULL is incorrect...even aside from the `(void*)` warning, it's possible (but incredibly rare) to have a computer in which the value of a null pointer is non-zero, and so the C standard allows NULL to be any value, it could be `(void*)INT_MAX` for example, which would make your statement false. I'm not sure what percentage of C code would fail to run correctly on such a system, but there's no need to encourage people to make that non-standard assumption and write more non-standard code. – Theodore Murdock Jul 29 '15 at 22:08
  • @TheodoreMurdock: Most cases that describe the behavior of `NULL` are talking about the behavior of pointer expressions that happen to equal null, rather than merely null pointer constants; and applying `!!` to a pointer expression will yield a value that cannot be compared with any other pointer expression that isn't a null pointer constant. – supercat Aug 06 '19 at 20:45
  • @supercat Are you saying that the standard specifies the behavior of negation of pointers such that the negation of a non-null pointer is always NULL, and the negation of NULL is always some non-NULL pointer, so long as the compiler knows the value is a pointer? I was assuming that boolean negation of a pointer would proceed by reinterpreting the bytes of the pointer as an integer value of the same width, following the 'everything is a memory word' philosophy of pre-typing versions of C, that resulted in so many types that silently degrade to other types in modern C. – Theodore Murdock Aug 07 '19 at 21:45
  • @TheodoreMurdock: The negation operator always yields a value of type `int` which is either one or zero. A literal zero, used in contexts requiring a pointer, will be converted to a null pointer, and because of this some implementations define `NULL` as a synonym for `0`. On those implementations, `!!NULL == NULL` would be true, but `!!NULL` would not be a pointer, but rather an integer value of zero. – supercat Aug 07 '19 at 21:54
  • 1
    @supercat But the question is whether `!!NULL == NULL` is true in C, as stated in this answer, not whether there exist some implementations in which this example of undefined behavior just so happens to be well-defined. – Theodore Murdock Aug 09 '19 at 23:02
  • @TheodoreMurdock: `NULL` is a macro whose definition is supplied by the implementation if `` is included. Whether the exact expression `!!NULL==NULL` would be true or whether it would be regarded as a constraint violation would depend upon how the implementation chooses to define that macro, but I can't think of any situation where that exact expression would be useful. – supercat Aug 10 '19 at 15:31
  • @supercat Of course it's not useful, it's meaningless garbage that shouldn't be in this answer. – Theodore Murdock Aug 13 '19 at 23:06
28

It is commonly (ab)used to convert any value into the ints 0 or 1 by repeated application of the boolean not operator, !.

For instance: !56 is 0, since 56 is "true" when viewed as a boolean. This means that !!56 is 1, since !0 is 1.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • 1
    You say "abused", but this is a common idiom. What do you suggest as a concise alternative? – PC Luddite Aug 01 '17 at 04:03
  • @PCLuddite Well I did say "(ab)used", hinting that the abuse accusation is a bit tongue in cheek". I would probably recommend `pt->aa[(ts->flags & MASK) != 0]` since I think that is much more clear and explicit. – unwind Aug 03 '17 at 19:41
  • it's quirky, but it's not one of the worst abuses of C, and definitely not one of the worst abuses of C++. That language was just built for code abuse. – PC Luddite Aug 03 '17 at 20:17
7

!E is the same as E == 0 so !!E is the same as (E == 0) == 0. !! is used to normalize booleans values.

ouah
  • 142,963
  • 15
  • 272
  • 331
4

It converts a number into a canonical Boolean.

And note that in this case it's critical to do so, since the result is being used to index an array.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
4

In C99 you can replace it by

#include <stdbool.h>


pt->aa[(bool)(ts->flags & MASK)] = -val;

Of course if your code is to be portable to C89 then you'd be better off doing the !! trick or

pt->aa[(ts->flags & MASK)!=0] = -val;

or

pt->aa[(ts->flags & MASK)?1:0] = -val;

The generated code will be certainly identical.

Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
2
  1. !!x is just a !(!x).
  2. if NULL is defined as 0 then !!NULL == !!0 == !(!0) == !(1) == 0.
1

!! is a decent way to quiet the compiler in certain situations such as assignment in a conditional with more than one expressions, e.g:

int _blah = 100;
int *blah;
if ( _blah > 100 && !!(blah = &_blah) ) {
// do stuff
}

I don't recommend this -- warnings are usually there to enforce good coding practice.

SilentDirge
  • 827
  • 9
  • 17