P99

◆ for()

for ( _Bool  p00 = 1; p00 && ({ { __VA_ARGS__ } 1; }); p00 = 0)

Prefer the statements in the argument list over the statement or block that follows.

The argument list should consist of a possibly empty list of statements, exactly as you would put them inside a { ... }. There is no restriction on the statements that you may put in the list: break, continue, return or goto should work as expected, and the list may even contain commas.

The dependent statement or block will in general not be executed unless they contain a valid jump target that is jumped to. Such a jump target may be a normal label or a case label.

char *str = malloc(25);
if (!str) goto CLEANUP;
.
.
P99_PREFER(fprintf(stderr, "Happy: all allocation went well!\n");)
CLEANUP: {
// Do some repair work and exit gracefully
fprintf(stderr, "Unhappy: something went wrong!\n");
}
See also
P99_AVOID

Only execute the depending statement or block if it is jumped into explicitly from the outer block.

This can be used to comment out code temporarily at source level. This macro is preferable to the common if (0) dialect that is used for the same purpose, since it has no problem with a dangling else.

This can also be used to handle some exceptional cases to which you want to jump explicitly, either by a goto or as a switch case.

With this the example from ::P99_PREFER reads simply

char *str = malloc(25);
if (!str) goto CLEANUP;
.
.
CLEANUP: {
// Do some repair work and exit gracefully
fprintf(stderr, "Unhappy: something went wrong!\n");
}
See also
P99_PREFER

Execute the statements in the argument list.

This is to have several statements executed in a place where syntactically only one statement (and not a { ... } block) is allowed.

The argument list should consist of a possibly empty list of statements, exactly as you would put them inside a { ... }. There is no restriction on the statements that you may put in the list: break, continue, return or goto should work as expected, and the list may even contain commas.

Traditionally this would be done with a construction like

do { __VA_ARGS__ } while(0)

That traditional construction changes the control flow in that break and continue statements would change their meaning inside the list.

See also
P99_PREFER
P99_AVOID

An exclusive case for a switch statement

This case will only be executed when the switch value is triggered and not if we fall through from a previous case.

switch(errno) {
case 0: break; // everything works fine
fprintf(stderr, "AUTSCH: call to schnoeck failed with unhandled case!\n");
perror("AUTSCH");
}
P99_XCASE ENOMEM :
fprintf(stderr, "Autsch: call to schnoeck didn't have enough memory!\n");
severe_error_occured = true;
P99_XCASE EINTR : {
fprintf(stderr, "Autsch: call to schnoeck was interrupted!\n");
// do something else in that case
}
// common clean up code comes here
errno = 0;
}

Please observe that these macros prefix exactly one statement or block and not a series of statements as a normal case would and that none has the semantic of a break. In particular:

  • EINTR and the default cases have { .. } around their statements such that they may execute several statements.
  • The severe_error_occured assignment is executed for the default and ENOMEM case.
  • The final cleanup code is executed by everybody but case 0:.

The default case analogous to P99_XCASE

Definition at line 327 of file p99_block.h.

P99_XCASE
#define P99_XCASE
P99_XDEFAULT
#define P99_XDEFAULT
P99_AVOID
#define P99_AVOID
errno
errno
Definition: p99_constraint.h:199