How to use a define inside a format string?

Viewed 7823

Say I have a character array:

#define LEN 10
char arr[LEN + 1];

Lets do some scanf operation to it:

scanf("Name: %s", arr);

This could be dangerous if someone is typing a name that is longer than 10 characters. So better use this:

scanf("Name: %10s", arr);

Well now I would run into trouble if LEN is changed. I would have to go through the whole code to correct every line where I used the 10 in context of arr. So I thought about somehting like this:

scanf("Name: %LENs", arr);

But this will not work.LEN is not resolved by the preprocessor beacuse it is used inside a string.

How to use a define inside a format string?

1 Answers

C joins adjacent string literals and you can stringify a preprocessor parameter with #, so the following should do the trick:

#define LEN 10

// this converts to string
#define STR_(X) #X

// this makes sure the argument is expanded before converting to string
#define STR(X) STR_(X)

[...]

scanf("Name: %" STR(LEN) "s", arr);

The macros are needed because with just #LEN, you'd end up with LEN expanded to 10, and with only one macro applying # to its argument, the result would be "LEN" (the argument wouldn't be expanded).

The preprocessor / compiler will transform this in the following steps:

1. scanf("Name: %" STR_(10) "s", arr);
2. scanf("Name: %" "10" "s", arr);
3. scanf("Name: %10s", arr);

In the last step, the string literals are joined into a single one.


On a side note, your scanf() format string would require the user to literally enter

Name: xyz

to actually match. I doubt this is what you wanted. You probably want something like this:

fputs("Name: ", stdout);
fflush(stdout);
scanf("%" STR(LEN) "s", arr);

Also consider not using scanf() at all. With e.g. fgets(), this whole preprocessor magic is obsolete. For reasons why you shouldn't use scanf(), see my beginners' guide away from scanf().

Related