【问题标题】:How to scan IP Address with fscanf如何使用 fscanf 扫描 IP 地址
【发布时间】:2018-06-20 04:02:44
【问题描述】:

如何在c中使用scanf扫描IP地址?

我已经是用户了:

scanf(" %d ", &ip_adress)

我应该使用

%d.%d.%d

或者有更简单的方法。

这是我从文件中读取信息的函数:

void read_tree_from(FILE *in, PC **root){
    char name[MAX_NAME];
    int ip_adress;
    int speed;
    while(fscanf(in, "%s %d %d", name, &ip_adress, &speed) != EOF){
        PC *new = create_new_item(name, ip_adress, speed);
        add_to_tree(new, root);
    }
}

但是当我运行程序时它工作正常,但在输出文件中它一团糟......

【问题讨论】:

  • fgets 然后解析。
  • scanf("%d.%d.%d.%d", &a, &b, &c, &d); 可以工作,但也可以接受像999.99.999.99999 这样的条目,它不是 IP 地址。如果您使用的是类 unix 系统,您也可以改用 inet_pton
  • 向我们展示你的文件内容,至少一行可以看到输入。
  • RACUNAR1 52.123.213.11 100。这是输入一台电脑的名称,它的IP地址和他的互联网速度
  • 与其将输出与fscanf(in, "%s %d %d", ....) != EOF 进行比较,因为它是代码不想要的1 值,而是与fscanf(in, "%s %d %d", name, &ip_adress, &speed) == 3 比较所需的成功转换次数。

标签: c ip scanf


【解决方案1】:

您可以使用格式说明符%hhu.%hhu.%hhu.%hhu,它读取无符号的 8 位值,您可以分别直接读取 ip 地址的 int 表示的 4 个字节:

int main () {

    const char* testLine = "aName 192.168.112.54 100";

    char name[100];
    int speed;

    volatile uint32_t ipAddress=0;
    unsigned char* ipAddressBytes = (unsigned char*)&ipAddress;


    if (sscanf(testLine, "%s %hhu.%hhu.%hhu.%hhu %d", name, ipAddressBytes+3, ipAddressBytes+2,ipAddressBytes+1,ipAddressBytes+0, &speed) == 6) {
        printf("%s %08X %d\n",name, ipAddress, speed);
    }

    return 0;   
}

输出:

aName C0A87036 100

Format %hhu 读入一个整数值并将其映射到 8 位;因此,在1025.168.112.54 无效的意义上,它不会检查有关 IP 地址的输入是否有效。但是,它避免了技术溢出,因为任何超过 8 位的部分都将被简单地忽略。所以之前提到的输入会产生01A87036

注意volatile-说明符,它告诉编译器它不应优化对该变量的访问;否则,编译器可能会假设 - 因为值没有明显改变 - 变量没有改变/没有初始化。

进一步注意,您必须注意您的环境是大端还是小端架构。

希望对你有帮助。

【讨论】:

  • ipAsArray+3 会导致依赖于字节序的解决方案。推荐uint8_t ipAddress[4];
  • @chux:大体上同意;但在我看来,OP 想要使用 int 类型,可能是由于给定的接口 create_new_item(name, ip_adress, speed);但也许我的假设是错误的;那么ipAddress[4]当然更独立了。
  • 我怀疑这将适用于 OP,但讨厌的抗锯齿规则开始发挥作用。代码不需要假设 ipAddresssscanf(testLine, "%s %hhu....", name, ipAsArray+3, ... 而更改,并且可以尝试打印未初始化的数据。
  • 正式地,scanf() spacification 表示使用%hhu 转换太大而无法放入unsigned char 的值会导致未定义的行为。 (如果该对象没有合适的类型,或者如果转换的结果无法在提供的空间中表示,则行为未定义。)另外,不管它值多少钱,%hhu.%hhu.%hhu.%hhu将转换" -234. +379. 456. 9",因为%hhu 将跳过空格并处理符号等。
  • @chux:关于未初始化数据的要点,谢谢。通过使ipAddress volatile 解决了这个问题。
【解决方案2】:

如何使用 fscanf 扫描 IP 地址

有了数据,fgets()有很多优势,包括比fscanf()更好的错误恢复,所以fgets/sscanf()解决方案

void read_tree_from(FILE *in, PC **root){
  char buffer [MAX_NAME + 50];
  // Read a line of input
  if (fgets(buffer, sizeof buffer, in)) {
    int ip_address;
    int speed;
    unsigned char octet[4];
    int n = 0;
    int namelen; 

    // This approach uses %n to record the scan offset - if it got that far 
    // %*s%n to scan over the name, all tht is needed is how long it is
    // %hhu to scan an `unsigned char`
    // " ." to scan spaces and then a '.'
    sscanf(buffer, "%*s%n %hhu .%hhu .%hhu .%hhu %d %n",
      &namelen, &octet[0], &octet[1], &octet[2], &octet[3], &speed, &n);

    // When `n > 0`, the complete scan occurred
    // buffer[n] != '\0' detects extra junk after the speed
    if (n == 0 || buffer[n] != '\0') {
      // failed scan
      return;
    }

    // Check data for validity 
    if (namelen >= MAX_NAME) {
      // name too long
      return;
    }

    buffer[namelen] = '\0';  // \0 terminate the name

    // form IP address.  I'd recommend `uint32_t` rather than `int`
    // The `1u*` insures code deals with unsigned promotions and shifts.  No sign extend
    ip_address = 1u*octet[0] << 24 | 1u*octet[1] << 16 | 1u*octet[2] << 8 | octet[3];

    PC *new = create_new_item(buffer, ip_adress, speed);
    add_to_tree(new, root);
    }
  }
}

或者有更简单的方法(?)

是的,如果代码不关心检测格式错误的数据,则可以使用许多快捷方式。生产代码检查错误数据。强大的检查将采用 buffer 并查找超出范围的数值(可能使用 strtoul)等。

【讨论】:

    【解决方案3】:

    我第一次尝试了这个,但它可能不起作用,因为我在代码的其他地方有一些错误,我认为这是导致错误的部分。但是当我修复了我的代码中的一些错误时它起作用了。

    while(fscanf(in, "%d %s %s %d", tmp_number, tmp_name, tmp_ip, &tmp_speed) != EOF){ RACUNAR *new = create_new_item(tmp_number, tmp_name, tmp_ip, tmp_speed); add_to_tree(new, root);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-04
      • 2010-12-17
      • 2019-03-05
      • 2012-07-14
      • 2022-12-21
      • 2016-05-04
      • 2015-05-01
      • 1970-01-01
      相关资源
      最近更新 更多