views:

62

answers:

1

I'm attempting to create an sscanf string literal to aid in buffer overrun prevention in C99. The goal is something like:

#define MAX_ARG_LEN   16

char arg[MAX_ARG_LEN] = "";

if (sscanf(arg, "%"(MAX_ARG_LEN-1)"X", &input) > 0)

The obvious "manual" solution is something like:

#define MAX_ARG_LEN   16
#define MAX_ARG_CHARS "15"

char arg[MAX_ARG_LEN] = "";

if (sscanf(arg, "%"MAX_ARG_CHARS"X", &input) > 0)

However, I would prefer something to automatically generate "%15X" given a buffer size of 16. This link is almost works for my application: http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string but it does not handle the -1.

Suggestions?

+5  A: 

Kernighan and Pike discuss this issue in their (excellent) book 'The Practice of Programming' and concluded that the most reliable and portable way to do this is to use sprintf() to generate the format string.

What you could do is define the macro as the length excluding terminal null, and then use that like this:

#define STR_EVALUATE(x)   #x
#define STRINGIFY(x)      STR_EVALUATE(x)
#define MAX_ARG_LEN 15
char arg[MAX_ARG_LEN+1] = "";

if (sscanf(arg, "%" STRINGIFY(MAX_ARG_LEN) "X", &input) > 0)
    ...

Or you could define MAX_ARG_STRLEN as 15 and MAX_ARG_LEN as MAX_ARG_STRLEN+1 and work accordingly.

Jonathan Leffler
In case anyone is interested, a longish explanation of why `STRINGIFY()` needs to be done the way Jonathan did it (with a layer of indirection): http://stackoverflow.com/questions/798221/c-macros-to-create-strings/798311#798311
Michael Burr
There's also the parallel discussion for token pasting (`##`) at [SO 1489932](http://stackoverflow.com/questions/1489932/c-preprocessor-and-concatenation/).
Jonathan Leffler
The +1 implementation above is a perfectly good solution - thanks!
Brett