Quick Links: |
Provide macros for use with NULL
-terminated variadic functions.
More...
NULL
-terminated variadic functions. BSLA_NULLTERMINATED | warn if last argument is not NULL |
BSLA_NULLTERMINATEDAT(ARG_IDX) | warn if argument at ARG_IDX is not NULL |
BSLA_NULLTERMINATED_IS_ACTIVE | 1 if BSLA_NULLTERMINATED is active |
BSLA_NULLTERMINATEDAT_IS_ACTIVE | 1 if BSLA_NULLTERMINATEDAT is active |
NULL
, or, in the case of BSLA_NULLTERMINATEDAT
, by NULL
at a certain index. Note that the terminating NULL
must actually be NULL
or, with C++11, nullptr
; passing 0 in its place will result in a warning. BSLA_NULLTERMINATED
This annotation on a variadic macro indicates that a warning should be issued unless the last argument to the function is explicitly NULL
.BSLA_NULLTERMINATEDAT(ARG_IDX)
This annotation on a variadic function indicates that a warning should be issued unless the argument at ARG_IDX
is NULL
, where ARG_IDX
is the number of arguments from the last, the last argument having ARG_IDX == 0
. Thus, BSLA_NULLTERMINATED
is equivalent to BSLA_NULLTERMINATEDAT(0)
.BSLA_NULLTERMINATED_IS_ACTIVE
BSLA_NULLTERMINATEDAT_IS_ACTIVE
In these two cases, X_IS_ACTIVE
is defined to 0 if X
expands to nothing and 1 otherwise.const char *
strings terminated by NULL
, concatenates the strings, separated by spaces, into a buffer. BSLA_NULL_TERMINATED
: void catStrings(char *outputBuffer, ...) BSLA_NULLTERMINATED; void catStrings(char *outputBuffer, ...) // The specified 'outputBuffer' is a buffer where the output of this // function is placed. The specified '...' is a 'NULL'-terminated list // of 'const char *' strings, which are to be copied into // 'outputBuffer', concatenated together and separated by spaces. The // behavior is undefined unless the '...' is a 'NULL'-terminated list // of 'const char *' arguments. { *outputBuffer = 0; va_list ap; va_start(ap, outputBuffer); const char *next; for (bool first = 1; (next = va_arg(ap, const char *)); first = 0) { ::strcat(outputBuffer, first ? "" : " "); ::strcat(outputBuffer, next); } va_end(ap); }
main
, we call catStrings
correctly: char buf[1000]; catStrings(buf, "Now", "you", "see", "it.", NULL); printf("%s\n", buf);
Now you see it.
catStrings" again and forget to add the terminating 'NULL
: catStrings(buf, "Now", "you", "don't."); printf("%s\n", buf);
.../bsla_nullterminated.t.cpp:412:47: warning: missing sentinel in function call [-Wsentinel] catStrings(buf, "Now", "you", "don't."); ^ , nullptr .../bsla_nullterminated.t.cpp:137:10: note: function has been explicitly marked sentinel here void catStrings(char *outputBuffer, ...) ^
const char *
strings terminated by NULL
, concatenates the strings, separated by spaces, into a buffer, and then there's an additional integer argument, interpreted as a boolean, that determines what is to be appended to the end of the buffer. BSLA_NULL_TERMINATEDAT(1)
: void catVerdict(char *outputBuffer, ...) BSLA_NULLTERMINATEDAT(1); void catVerdict(char *outputBuffer, ...) // The specified 'outputBuffer' is a buffer where output is to be // placed. All but the last 2 of the specified '...' arguments are // 'const char *' strings to be concatenated together into // 'outputBuffer', separated by spaces. The second-to-last argument is // to be 'NULL', and the last argument is an 'int' interpreted as a // boolean to determine whether the buffer is to end with a verdict of // "guilty" or "not guilty". The behavior is undefined unless the // types of all the arguments are correct and the second to last // argument is 'NULL'. { *outputBuffer = 0; va_list ap; va_start(ap, outputBuffer); const char *next; for (bool first = 1; (next = va_arg(ap, const char *)); first = 0) { ::strcat(outputBuffer, first ? "" : " "); ::strcat(outputBuffer, next); } const bool guilty = va_arg(ap, int); ::strcat(outputBuffer, guilty ? ": guilty" : ": not guilty"); va_end(ap); }
main
, we call catVerdict
correctly: char buf[1000]; catVerdict(buf, "We find the", "defendant,", "Bugs Bunny", NULL, 0); printf("%s\n", buf);
We find the defendant, Bugs Bunny: not guilty
catVerdict
with no NULL
passed, and get a warning (and probably a core dump if we ran it): catVerdict(buf, "We find the", "defendant,", "Wile E. Coyote", 1); printf("%s\n", buf);
.../bsla_nullterminated.t.cpp:447:70: warning: missing sentinel in function call [-Wsentinel] catVerdict(buf, "We find the", "defendant,", "Wile E. Coyote", 1); ^ , nullptr .../bsla_nullterminated.t.cpp:171:10: note: function has been explicitly marked sentinel here void catVerdict(char *outputBuffer, ...) ^
catVerdict
and forget to put the integer that indicates guilt or innocence after the NULL
. This means that NULL
is happening at index 0, not index 1, which violates the requirement imposed by the annotation: catVerdict(buf, "We find the", "defendant,", "Road Runner", NULL); printf("%s\n", buf);
.../bsla_nullterminated.t.cpp:471:67: warning: missing sentinel in function call [-Wsentinel] catVerdict(buf, "We find the", "defendant,", "Road Runner", NULL); ^ , nullptr .../bsla_nullterminated.t.cpp:171:10: note: function has been explicitly marked sentinel here void catVerdict(char *outputBuffer, ...) ^