Skip to main content

What is ":-!!' in C code?


I bumped into this strange macro code in /usr/include/linux/kernel.h :




/* Force a compilation error if condition is true, but also produce a
result (of value 0 and type size_t), so the expression can be used
e.g. in a structure initializer (or where-ever else comma expressions
aren't permitted). */
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); }))



What does :-!! do?


Source: Tips4allCCNA FINAL EXAM

Comments

  1. This is, in effect, a way to check whether the expression e can be evaluated to be 0, and if not, to fail the build.

    The macro is somewhat misnamed; it should be something more like BUILD_BUG_OR_ZERO, rather than ...ON_ZERO. (There have been occasional discussions about whether this is a confusing name.)

    You should read the expression like this:

    sizeof(struct { int: -!!(e); }))



    (e): Declare an expression e.
    !!(e): Negate it twice. This produces 0 if e was 0 originally, or a nonzero positive number
    if it wasn't.
    -!!(e): Multiply the value by -1. This results in 0 if step 2 was 0, or a negative number if it wasn't.
    struct{int: -!!(0);} --> struct{int: 0;}: If it was zero, then we declare a struct with an integer bitfield that has width zero. Everything is fine and we proceed as normal.
    struct{int: -!!(1);} --> struct{int: -1;}: On the other hand, if it isn't zero, then it will be some negative number. Declaring a bitfield with negative width is a compilation error.


    So we'll either wind up with a bitfield that has width 0 in a struct, which is fine, or a bitfield with negative width, which is a compilation error. Then we take sizeof that field, so we get a size_t with the appropriate width (which will be zero in the case where e is zero).



    Some people have asked: Why not just use an assert?

    keithmo's answer here has a good response:


    These macros implement a compile-time test, while assert() is a run-time test.


    Exactly right. You don't want to detect problems in your kernel at runtime that could have been caught earlier! It's a critical piece of the operating system. To whatever extent problems can be detected at compile time, so much the better.

    ReplyDelete
  2. The : is a bitfield. As for !!, that is logical double negation and so returns 0 for false or 1 for true. And the - is a minus sign, i.e. arithmetic negation.

    It's all just a trick to get the compiler to barf on invalid inputs.

    Consider BUILD_BUG_ON_ZERO. When -!!(e) evaluates to a negative value, that produces a compile error. Otherwise -!!(e) evaluates to 0, and a 0 width bitfield has size of 0. And hence the macro evaluates to a size_t with value 0.

    The name is weak in my view because the build in fact fails when the input is not zero.

    BUILD_BUG_ON_NULL is very similar, but intended for use with a pointer input.

    ReplyDelete
  3. Some people seem to be confusing these macros with assert().

    These macros implement a compile-time test, while assert() is a run-time test.

    ReplyDelete
  4. It's creating a size 0 bitfield if the condition is false, but a size -1 (-!!1) bitfield if the condition is true/non-zero. In the former case, there is no error and the struct is initialized with an int member. In the latter case, there is a compile error (and no such thing as a size -1 bitfield is created, of course).

    ReplyDelete

Post a Comment

Popular posts from this blog

Why is this Javascript much *slower* than its jQuery equivalent?

I have a HTML list of about 500 items and a "filter" box above it. I started by using jQuery to filter the list when I typed a letter (timing code added later): $('#filter').keyup( function() { var jqStart = (new Date).getTime(); var search = $(this).val().toLowerCase(); var $list = $('ul.ablist > li'); $list.each( function() { if ( $(this).text().toLowerCase().indexOf(search) === -1 ) $(this).hide(); else $(this).show(); } ); console.log('Time: ' + ((new Date).getTime() - jqStart)); } ); However, there was a couple of seconds delay after typing each letter (particularly the first letter). So I thought it may be slightly quicker if I used plain Javascript (I read recently that jQuery's each function is particularly slow). Here's my JS equivalent: document.getElementById('filter').addEventListener( 'keyup', function () { var jsStart = (new Date).getTime()...

Is it possible to have IF statement in an Echo statement in PHP

Thanks in advance. I did look at the other questions/answers that were similar and didn't find exactly what I was looking for. I'm trying to do this, am I on the right path? echo " <div id='tabs-".$match."'> <textarea id='".$match."' name='".$match."'>". if ($COLUMN_NAME === $match) { echo $FIELD_WITH_COLUMN_NAME; } else { } ."</textarea> <script type='text/javascript'> CKEDITOR.replace( '".$match."' ); </script> </div>"; I am getting the following error message in the browser: Parse error: syntax error, unexpected T_IF Please let me know if this is the right way to go about nesting an IF statement inside an echo. Thank you.