2

I want to parse an ip from file using fscanf (C code using gcc). so, I want to do:

char myip[INET_ADDRSTRLEN];
fscanf(file, "%16s", myip);

but, I don't want to hardcode the number 16, so I'm trying to use macro, but it doesn't work.

#define _STRIFY(x) #x
char myip[INET_ADDRSTRLEN];
fscanf(file, "%" _STRIFY(INET_ADDRSTRLEN) "s", myip);

here is the error I get

unknown conversion character type 'N' format

so what is wrong with my code ?

thanks for your help :)

ramone
  • 266
  • 1
  • 2
  • 10
  • 2
    Don't forget that if your buffer is of length INET_ADDRSTRLEN, the number to be specified to `sprintf()` is INET_ADDRSTRLEN-1. This makes macro-based solutions hard. – Jonathan Leffler Sep 26 '12 at 18:24

2 Answers2

4

How about this?

char format[14];
sprintf(format, "%%%ds", INET_ADDRSTRLEN-1);
fscanf(file, format, myip);
cristis
  • 1,986
  • 16
  • 22
  • +1: with an appropriate definition for `s`, which might be better named `format`, perhaps. This works best if INET_ADDRSTRLEN evaluates to an expression. – Jonathan Leffler Sep 26 '12 at 18:22
  • 1
    As noted in a comment to the main question, the length needs to be `INET_ADDRSTRLEN - 1` to avoid overflow of a buffer of length `INET_ADDRSTRLEN`; the null is not included in the length in `scanf()` et al. – Jonathan Leffler Sep 26 '12 at 18:43
2

Use this:

#define stringify_1(x...)  #x
#define stringify(x...)    stringify_1(x)

char myip[INET_ADDRSTRLEN];
fscanf(file, "%" stringify(INET_ADDRSTRLEN) "s", myip);

These are the stringify function-like macros used in the Linux kernel.

See in my comments you are vulnerable to a buffer overflow if you use the same value for the buffer size and the size in the conversion specification. Use for example INET_ADDRSTRLEN + 1 in the buffer declaration to avoid the possibility of the overflow.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • +1: This works when INET_ADDSTRLEN evaluates to a simple number; not so hot if it evaluates to an expression. – Jonathan Leffler Sep 26 '12 at 18:20
  • @JonathanLeffler by the way there is an off-by-one buffer overflow in his program, if the buffer is `INET_ADDSTRLEN` bytes, he'd need `INET_ADDSTRLEN - 1` for the `%s` conversion specification as the null character is not counted. As he cannot use an expression for the `stringify` macro, a solution is to declare `myip` with size `INET_ADDRSTRLEN + 1`. – ouah Sep 26 '12 at 18:27
  • @JonathanLeffler actually I'm just seeing you wrote a similar comment in the OP question – ouah Sep 26 '12 at 18:29
  • You'll need to remove or seriously modify your `*` solution; in `scanf()`, that's assignment suppression, not 'take length of argument' like it would be in `printf()`. Even in `printf()`, you'd need a cast to `int` on the result of `sizeof` since `size_t` is not guaranteed to the same size as `int`. – Jonathan Leffler Sep 26 '12 at 18:41
  • @JonathanLeffler well spotted, I thought the behavior was the same as with `fprintf`. – ouah Sep 26 '12 at 18:45