【问题标题】:fscanf fixed string size using macrofscanf 使用宏固定字符串大小
【发布时间】:2012-09-26 18:11:34
【问题描述】:

我想使用 fscanf(使用 gcc 的 C 代码)从文件中解析 ip。 所以,我想做:

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

但是,我不想硬编码数字 16,所以我尝试使用宏,但它不起作用。

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

这是我得到的错误

unknown conversion character type 'N' format

那么我的代码有什么问题?

感谢您的帮助:)

【问题讨论】:

  • 不要忘记,如果您的缓冲区长度为 INET_ADDRSTRLEN,则要指定给 sprintf() 的数字是 INET_ADDRSTRLEN-1。这使得基于宏的解决方案变得困难。

标签: string gcc macros scanf


【解决方案1】:

这个怎么样?

char format[14];
sprintf(format, "%%%ds", INET_ADDRSTRLEN-1);
fscanf(file, format, myip);

【讨论】:

  • +1: 为s 提供适当的定义,也许将其命名为format 会更好。如果 INET_ADDRSTRLEN 计算结果为表达式,则此方法效果最佳。
  • 正如对主要问题的评论中所述,长度需要为 INET_ADDRSTRLEN - 1 以避免长度为 INET_ADDRSTRLEN 的缓冲区溢出; scanf() 等的长度中不包含 null。
【解决方案2】:

使用这个:

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

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

这些是 Linux 内核中使用的类似字符串化函数的宏。

在我的 cmets 中看到,如果您对缓冲区大小和转换规范中的大小使用相同的值,那么您很容易受到缓冲区溢出的影响。例如在缓冲区声明中使用INET_ADDRSTRLEN + 1 以避免溢出的可能性。

【讨论】:

  • +1:当 INET_ADDSTRLEN 计算为简单数字时有效;如果计算结果为表达式,则不会那么热。
  • @JonathanLeffler 顺便说一下,他的程序中存在一个逐一的缓冲区溢出,如果缓冲区是 INET_ADDSTRLEN 字节,他需要 INET_ADDSTRLEN - 1 用于 %<size>s 转换规范因为不计算空字符。由于他不能对stringify 宏使用表达式,解决方案是声明myip 大小为INET_ADDRSTRLEN + 1
  • @JonathanLeffler 实际上我只是看到你在 OP 问题中写了类似的评论
  • 您需要删除或认真修改您的* 解决方案;在scanf() 中,这是分配抑制,而不是像在printf() 中那样的“取参数长度”。即使在printf() 中,您也需要将sizeof 的结果转换为int,因为size_t 的大小不能保证与int 相同。
  • @JonathanLeffler 很好看,我认为行为与fprintf 相同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-12
  • 1970-01-01
  • 1970-01-01
  • 2018-05-25
  • 2017-01-03
  • 2021-01-11
  • 2014-12-19
相关资源
最近更新 更多