2012-09-26 57 views
2

我想使用fscanf(使用gcc的C代码)从文件解析ip。 所以,我想做的事:fscanf使用宏固定字符串大小

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 

那么,什么是错我的代码?

感谢您的帮助:)

+2

不要忘记,如果你的缓冲区的长度是INET_ADDRSTRLEN,那么被指定为'sprintf()'的数字是INET_ADDRSTRLEN-1。这使得宏观解决方案变得困难。 –

回答

4

这个怎么样?

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

+1:有's'的适当定义,可能会更好地命名'format'。如果INET_ADDRSTRLEN评估为一个表达式,这效果最好。 –

+1

正如在对主要问题的评论中指出的那样,为避免长度为“INET_ADDRSTRLEN”的缓冲区溢出,长度需要为“INET_ADDRSTRLEN - 1”; 'scanf()'等中不包含空值。 –

2

使用此:

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

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

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

在我的评论中看到,如果在转换规范中对缓冲区大小和大小使用相同的值,则容易发生缓冲区溢出。在缓冲区声明中使用例如INET_ADDRSTRLEN + 1以避免溢出的可能性。

+0

+1:这适用于INET_ADDSTRLEN评估为简单数字;如果它评估为一个表达式,则不会太热。 –

+0

@JonathanLeffler在他的程序中有一个off-by-one缓冲区溢出,如果缓冲区是INET_ADDSTRLEN字节,他需要'INET_ADDSTRLEN-1'作为'% s''转换规范作为null字符不计算在内。由于他不能为'stringify'宏使用表达式,因此解决方案是声明大小为'INET_ADDRSTRLEN + 1'的myip。 – ouah

+0

@JonathanLeffler其实我只是看到你在OP问题 – ouah