27

What are typical uses of null statement

;

in C ?

I know that it is basically used to skip expression where it is expected by the compiler, but here I'm interested only in real-world examples of such use cases.

Agnius Vasiliauskas
  • 10,935
  • 5
  • 50
  • 70
  • 9
    I prefer `{}` if you need an empty statement, it looks to me less likely to be accidental. So "never" ;-) – Steve Jessop Apr 08 '11 at 18:48
  • 1
    `{}` is not useful in some of the contexts `;` would be useful in. – R.. GitHub STOP HELPING ICE Apr 08 '11 at 21:43
  • @R..: which ones? As an empty statement, I mean - we've already got that in `for` statements you might write `(;` or `;;`, and since the parts omitted aren't statements (rather declarations or expressions), `{}` won't do. Obviously there are places in C where you can't just replace a semi-colon with `{}`. Almost all of them. But that's not what I meant :-) – Steve Jessop Apr 09 '11 at 20:04

13 Answers13

25

It's typically the side-effect of a code block that was stripped by the preprocessor, like

#if DEBUG
    #define ASSERT(_x) Assert(_x)
#else
    #define ASSERT(_x)
#endif


ASSERT(test);    // Results in null statement in non-debug builds

That, or in loops where your condition already contains whatever needs to be done in each iteration.

EboMike
  • 76,846
  • 14
  • 164
  • 167
  • There is a typo in the example: `Assert(x)` should be replaced by `Assert(_x)` since `_x` has been used as the parameter name (I can't edit the answer as edits must be at least 6 characters). – vinc17 Aug 04 '16 at 14:13
  • Also, for the `#else` case, I would rather use `#define ASSERT(_x) ((void) 0)` so that an error be reported when one forgets a semicolon, such as in: `ASSERT(test1) ASSERT(test2);` But in this case, there isn't a null statement any longer. – vinc17 Aug 04 '16 at 14:17
18
while (*(dst++) = *(src++))
    ;
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
16

After a label at the end of a function (or more precisely, at the end of any block), e.g.

void foo(void)
{
    // ...

exit:
    ;
}
Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 7
    I would totally put `return;` instead. – Steve Jessop Apr 08 '11 at 18:51
  • 14
    @steve The label can come at the end of any block, so `return` isn't always appropriate. An example is a multiply nested loop when you want to continue an outer loop from within inner loop (of course, you could use `label: continue; }` instead of `label: ;}`). – Jim Balter Apr 08 '11 at 19:21
  • @Jim: or you could write `continue;` instead of `goto label;`. I believe there are uses for this, possibly even ones less crazy than, "I go to the label defined by some macro, hence I can't substitute continue in one special case". I just don't think I've ever seen one. – Steve Jessop Apr 09 '11 at 19:58
  • 1
    @Steve Please read what I wrote again: "continue an outer loop from within inner loop" -- just writing `continue;` would continue the wrong loop. The Bliss language had no goto but did have loop labels for break/continue of outer loops; too bad C doesn't have that. – Jim Balter Apr 11 '11 at 05:52
  • 1
    @Jim: OK, I see. Yes, continuing an outer for loop requires a do-nothing statement. Loop labels are very rarely missed, but on the occasions when you do want one it's particularly annoying they aren't there, since it leads to silly arguments whether you should refactor into extra functions to avoid using "goto". – Steve Jessop Apr 11 '11 at 08:55
5
while (somethingWithSideEffects()) ;
zoul
  • 102,279
  • 44
  • 260
  • 354
4

I have used it, albeit rarely, in a possibly unusual situation (and one that some/many people would find wrong). I have had to sometimes write a very complex if condition without an else clause where the if condition has to be negated. Obviously it can be something like this:

if ( !( overly complex condition ) )
  {
  do stuff
  }

It sometimes makes more sense (to me at least) to think of it in terms of positive logic. In other words, if the overly complex condition holds true, I don't want the code to run. So I have instead written it as:

if ( overly complex condition )
  ;  // do nothing
else
  {
  do stuff
  }  
Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110
  • 1
    I find it's better to break it down into multiple `if`. It's still going to be complex if you remove the `!( )`. – ikegami Apr 08 '11 at 19:17
2

A somewhat unusual use -- but for which I really appreciate the existence of the null statement -- is when I have two conditions and two actions which I find I can most naturally express like this:

if(condition1)
     /* do nothing */ ;                                                      
else if(condition2)
     do_something;                                                           
else do_something_else;                                                      

Often condition1 tests that everything is okay, but if it's not, condition2 distinguishes between two different exception actions do_something and do_something_else.

This isn't the only way to express such a thing, of course. It would be possible to repeat condition1:

if(!condition1 && condition2)
    do_something;                                                           
else if(!condition1)
    do_something_else;

But that seems inferior, because it repeats condition1. Or it would be possible to use nested if statements:

if(!condition1) {
    if(condition2)
         do_something;                                                   
    else do_something_else;                                              
}

But of course nested if statements are notoriously prone to overcomplication and obfuscation, too. So I often prefer the first version, with the null statement.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
2

Example:

 while (!kbhit())
     ;

Should be self-explanatory.

user541686
  • 205,094
  • 128
  • 528
  • 886
2

Unit tests for a compliant compiler.

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
2

I can think of scanf validation. scanf gets stuck when user didn't give the correct input. So, to prevent scanf from being stuck, characters until end of line must be removed.

if( scanf("%d",&integer) == 0 )
{
    while( getchar() != '\n' ) ;
    // ....
}
Lou Franco
  • 87,846
  • 14
  • 132
  • 192
Mahesh
  • 34,573
  • 20
  • 89
  • 115
1

The only uses I can think of are:

1- At the end of a loop, where the operations are already encoded within the loop statements. e.g. while(a[i--]);

2- At the end of a label, where no operation is needed to be done. e.g. Label: ;

Pirooz
  • 1,268
  • 1
  • 13
  • 24
1

i was wondering how to write a null expression into the inline if and came up with this. it compiles and works.

condition ? x = 1 : "do nothing";

fun stuff.

0

It's more of a null expression rather than a null statement, but it's often found in for loops.

for (;;)                 // Loop "forever"

for (int i=10; i--; )    // 9..0

etc

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 8
    Technically that's not a null statement. 6.8.3 of C99 defines a null statement as an *expression-statement* with no *expression*, whereas this is an *iteration-statement* with fewer than 3 of its optional *expression* s. The three things in the parentheses of a for loop aren't statements, they're semi-colon-separated expressions, which is why you can't write `for(int i=10; i--; {})` Nit-picky, I know :-) – Steve Jessop Apr 08 '11 at 18:56
  • 4
    @Steve Jessop, I did say it wasn't a null statement, but thanks for the extra technical details. – ikegami Apr 08 '11 at 19:13
0

The only place I use null statements is when a case begins with a declaration:

switch(x) {
  case 5: ;
    int y = makeValue(z);
    ...
    break;
  ...
}

This will not compile if you remove the null statement that the case begins with. The reason is that a label cannot precede a declaration.