21

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?

8
  • 2
    You don't use a define inside a format string. You use sprintf() to build the format string and pass that to scanf. Commented Nov 17, 2017 at 8:33
  • 2
    @jwdonahue Bad suggestion. Commented Nov 17, 2017 at 8:40
  • @iBug, and you have a better suggestion? Commented Nov 17, 2017 at 8:45
  • 1
    @jwdonahue Not a bad suggestion in general, but if you can use the preprocessor, it's always better (no runtime overhead). Commented Nov 17, 2017 at 8:47
  • 2
    @iBug this discussion is pointless. You plagiarized everything, in many steps following my answer, which mods can see. You're obviously just hunting for reps and badges. This is not a game and plagiarism won't be tolerated. Commented Nov 17, 2017 at 9:23

1 Answer 1

36

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().

Sign up to request clarification or add additional context in comments.

9 Comments

@eDeviser these macros may appear in a standard header, but I doubt it. They aren't specified by the C standard, so define them yourself.
@FelixPalmen.: By the way..the scanf is containing Name is..etc..A rare use I would say.
@eDeviser I added some info you might find useful.
Definitely the right answer, if someone insists on using scanf. It would be wise to add a clear comment just before #define LEN mentioning that it must be a simple decimal integer and not an expression etc.
Why is it better to use this solution, rather than just putting #X within scanf?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.