在为学校做一些项目时,遇到以下问题:

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',而不是01! )。您知道数据(或需要知道数据)—您的电话。

我会注意到您的结构浪费了大量空间。开头的一个字节字段后面有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/

10-11 07:07