在为学校做一些项目时,遇到以下问题:sscanf
读取与期望值不同的值。
我想读这样的东西:
1 0 185336079 0 0 168231418 -256 0 255 1
2 0 185336079 -256 0 168231418 -256 0 255 2
3 0 185336079 -256 0 168231418 -256 0 255 3
4 0 185336079 0 0 0 0 0 255 4
这是我目前使用的代码:
FILE *fd = open_fd("/proc/firewall", "r");
while ((read = getline(&line, &len, fd)) != -1) {
sscanf(line, "%d %c %d %d %d %d %d %d %c %c\n", &num,
&rule_u.inbound_outbound,
&rule_u.source_ip,
&rule_u.source_netmask,
&rule_u.source_port,
&rule_u.destination_ip,
&rule_u.destination_netmask,
&rule_u.destination_port,
&rule_u.protocol,
&rule_u.action);
printf("scanf read rule action : %c\n", rule_u.action);
printf("sscanf whole line:\n%s\n",line);
convert_rule_from_u();
print_rule();
}
上面的代码生成的输出如下:
scanf read rule action : 5
sscanf whole line:
1 0 185336079 0 0 168231418 -256 0 255 1
scanf read rule action : 5
sscanf whole line:
2 0 185336079 -256 0 168231418 -256 0 255 2
scanf read rule action : 5
sscanf whole line:
3 0 185336079 -256 0 168231418 -256 0 255 3
scanf read rule action : 5
sscanf whole line:
4 0 185336079 0 0 0 0 0 255 4
预期的输出应为以下内容:
scanf read rule action : 1
sscanf whole line:
1 0 185336079 0 0 168231418 -256 0 255 1
scanf read rule action : 2
sscanf whole line:
2 0 185336079 -256 0 168231418 -256 0 255 2
scanf read rule action : 3
sscanf whole line:
3 0 185336079 -256 0 168231418 -256 0 255 3
scanf read rule action : 4
sscanf whole line:
4 0 185336079 0 0 0 0 0 255 4
rule_u struct
typedef struct rule_struct_u {
unsigned char inbound_outbound;
unsigned int source_ip;
unsigned int source_netmask;
unsigned int source_port;
unsigned int destination_ip;
unsigned int destination_netmask;
unsigned int destination_port;
unsigned char protocol;
unsigned char action;
} rule_struct_u;
我究竟做错了什么?
最佳答案
通常,对于scanf()
函数族在格式字符串中使用尾随空格是个坏主意-有关更多详细信息,请参见Trailing blank in scanf()
format string。如果函数是sscanf()
或它的亲戚之一,它是从字符串而不是文件流中读取的,则不是灾难。
但是,您还遇到了最后一个倒数第二个%c
不能读取所有255
的问题-您需要第二个倒数第二个%d
(或者可能是%hhd
或%hhu
)列,并应查看所有其他%c列;也许他们也应该是数字?
所以您说应该像这样:sscanf(line, "%d%hhu%d%d%d%d%d%d%hhu%hhu",...
-可以吗?我认为它之前已经阅读了整个255
;我正在玩它,并且它正在运行,或者至少看起来像它。
转换规范之间的空格可以;他们使它更具可读性。字符串末尾的换行符表示“读取空白,直到到达非空白为止”,如果输入来自(磁盘)文件或字符串,则可以,但是如果输入来自来自终端,管道,FIFO,套接字。
直到输入上出现下一条消息时,对scanf()
的调用才会返回。它需要换行符,空格或制表符以外的其他内容来表示“仅此而已”。那可能不是您想要的。
示例数据上的最后一个字段不是单个字符。您可能想要一个适合无符号字符的数字,因此%hhu
是合适的。其他两个%c
列仅在数据中保留零,但是如果它们可以容纳大于9的数字,则需要%hhu
。
“入站/出站”列可能为0或1,因此%c
可能就可以了(但请注意,值将是'0'
和'1'
,而不是0
和1
! )。您知道数据(或需要知道数据)—您的电话。
我会注意到您的结构浪费了大量空间。开头的一个字节字段后面有3个字节的填充,结尾处还有两个字节的填充。考虑将三个无符号char字段彼此相邻移动以节省每个结构4个字节(您仍然有1个填充字节,但这是对5个的改进)。考虑一下这是否重要(机会并不重要)。
另外,您应该测试sscanf()
或scanf()
的返回值,以确保获得正确的输入。
if (sscanf(line, "%d %hhu %d %d %d %d %d %d %hhu %hu", &num,
&rule_u.inbound_outbound,
&rule_u.source_ip,
&rule_u.source_netmask,
&rule_u.source_port,
&rule_u.destination_ip,
&rule_u.destination_netmask,
&rule_u.destination_port,
&rule_u.protocol,
&rule_u.action) != 10)
{
…handle error…do not pass go, do not collect $200…
}
关于c - 行尾怪异的sscanf行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48143601/