C语言将点分十进制的IP字符串转成4个整数

最近在做lldp的snmp返回值时需要做这样的转换处理:C语言将点分十进制的IP字符串转成4个整数。

这里用两种方式:

  1. sscanf格式化处理
  2. 用 inet_aton函数将ip字符串转成32位的整形,然后再根据bit转成对应的4个整数。
  • man命令可以确认下sscanf和inet_aton的返回值,以确认处理成功还是失败。
  • 字节序问题:inet_aton后统一用网络字节序,避免出错。

sscanf

c 复制代码
#include <stdio.h>

// 1 succeed, 0 failed
int parse_ip_sscanf(const char *ip_str, int *a, int *b, int *c, int *d) {
    return sscanf(ip_str, "%d.%d.%d.%d", a, b, c, d) == 4;
}

int main() {
    // 定义点分十进制的 IP 字符串
    const char *ip_str = "192.168.1.1";

    // 定义变量存储解析结果
    int a, b, c, d;

	if (0 == parse_ip_sscanf(ip_str, &a, &b, &c, &d)) {
		printf("parse_ip_sscanf failed\n");
	} else {
		printf("parse done: %d %d %d %d\n", a, b, c, d);
	}
	return 0;
}

inet_aton + ntol

c 复制代码
#include <stdio.h>
#include <arpa/inet.h>

#define u8 unsigned char

// 1 succeed, 0 failed
int parse_ip_inet_aton(const char *ip_str, int *a, int *b, int *c, int *d) {
	u8 *p = NULL;
    in_addr_t ip_int;
    if (inet_aton(ip_str, (struct in_addr *)&ip_int) == 0) {
        return 0;  // 解析失败
    }
    p = (u8 *)&ip_int;
    *a = p[0];
    *b = p[1];
    *c = p[2];
    *d = p[3];
    return 1;  // 解析成功
}

int main() {
    // 定义点分十进制的 IP 字符串
    const char *ip_str = "192.168.1.1";

    // 定义变量存储解析结果
    int a, b, c, d;

	if (0 == parse_ip_inet_aton(ip_str, &a, &b, &c, &d)) {
		printf("parse_ip_sscanf failed\n");
	} else {
		printf("parse done: %d %d %d %d\n", a, b, c, d);
	}
	return 0;
}

哪个效率高点?

这里用的是固定的字符串跑的测试,不太严谨。。。可以考虑随机生成1~255的数字组成ip字符串,然后再跑下测试。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>

#define TEST_COUNT 1000000  // 测试次数

// 使用 sscanf 解析 IP 地址
int parse_ip_sscanf(const char *ip_str, int *a, int *b, int *c, int *d) {
    return sscanf(ip_str, "%d.%d.%d.%d", a, b, c, d) == 4;
}

// 使用 inet_aton 解析 IP 地址
int parse_ip_inet_aton(const char *ip_str, int *a, int *b, int *c, int *d) {
    in_addr_t ip_int;
    if (inet_aton(ip_str, (struct in_addr *)&ip_int) == 0) {
        return 0;  // 解析失败
    }
    ip_int = ntohl(ip_int);
    *a = (ip_int >> 24) & 0xFF;
    *b = (ip_int >> 16) & 0xFF;
    *c = (ip_int >> 8) & 0xFF;
    *d = ip_int & 0xFF;
    return 1;  // 解析成功
}

int main() {
    // 定义点分十进制的 IP 字符串
    const char *ip_str = "192.168.1.1";

    // 定义变量存储解析结果
    int a, b, c, d;

    // 记录失败的次数
    int sscanf_fail_count = 0;
    int inet_aton_fail_count = 0;

    // 测试 sscanf 方式
    clock_t start = clock();
    for (int i = 0; i < TEST_COUNT; i++) {
        if (0 == parse_ip_sscanf(ip_str, &a, &b, &c, &d)) {
            sscanf_fail_count++;
        }
    }
    clock_t end = clock();
    double sscanf_time = (double)(end - start) / CLOCKS_PER_SEC;
    printf("sscanf 方式耗时: %.6f 秒\n", sscanf_time);
    printf("sscanf 方式失败次数: %d\n", sscanf_fail_count);

    // 测试 inet_aton 方式
    start = clock();
    for (int i = 0; i < TEST_COUNT; i++) {
        if (0 == parse_ip_inet_aton(ip_str, &a, &b, &c, &d)) {
            inet_aton_fail_count++;
        }
    }
    end = clock();
    double inet_aton_time = (double)(end - start) / CLOCKS_PER_SEC;
    printf("inet_aton 方式耗时: %.6f 秒\n", inet_aton_time);
    printf("inet_aton 方式失败次数: %d\n", inet_aton_fail_count);

    // 比较两种方式的效率
    if (sscanf_time < inet_aton_time) {
        printf("sscanf 方式更快,效率高出 %.2f 倍\n", inet_aton_time / sscanf_time);
    } else {
        printf("inet_aton 方式更快,效率高出 %.2f 倍\n", sscanf_time / inet_aton_time);
    }

    return 0;
}

/*
sscanf 方式耗时: 0.104025 秒
sscanf 方式失败次数: 0
inet_aton 方式耗时: 0.027499 秒
inet_aton 方式失败次数: 0
inet_aton 方式更快,效率高出 3.78 倍
*/

修改ip随机生成一百万次,测试:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <time.h>

#define TEST_COUNT 1000000  // 测试次数

// 生成一个随机的合法 IP 地址字符串
void generate_random_ip(char *ip_str) {
    sprintf(ip_str, "%d.%d.%d.%d",
            rand() % 256, rand() % 256, rand() % 256, rand() % 256);
}

// 使用 sscanf 解析 IP 地址
int parse_ip_sscanf(const char *ip_str, int *a, int *b, int *c, int *d) {
    return sscanf(ip_str, "%d.%d.%d.%d", a, b, c, d) == 4;
}

// 使用 inet_aton 解析 IP 地址
int parse_ip_inet_aton(const char *ip_str, int *a, int *b, int *c, int *d) {
    in_addr_t ip_int;
    if (inet_aton(ip_str, (struct in_addr *)&ip_int) == 0) {
        return 0;  // 解析失败
    }
    ip_int = ntohl(ip_int);
    *a = (ip_int >> 24) & 0xFF;
    *b = (ip_int >> 16) & 0xFF;
    *c = (ip_int >> 8) & 0xFF;
    *d = ip_int & 0xFF;
    return 1;  // 解析成功
}

int main() {
    // 初始化随机数种子
    srand(time(NULL));

    // 定义变量存储解析结果
    int a, b, c, d;

    // 记录失败的次数
    int sscanf_fail_count = 0;
    int inet_aton_fail_count = 0;

    // 动态分配堆空间存储 IP 地址数组
    char (*ip_array)[16] = malloc(TEST_COUNT * sizeof(*ip_array));
    if (ip_array == NULL) {
        printf("内存分配失败!\n");
        return 1;
    }

	// 随机生成 IP 地址数组
    for (int i = 0; i < TEST_COUNT; i++) {
        generate_random_ip(ip_array[i]);
    }

    // 测试 sscanf 方式
    clock_t start = clock();
    for (int i = 0; i < TEST_COUNT; i++) {
        if (!parse_ip_sscanf(ip_array[i], &a, &b, &c, &d)) {
            sscanf_fail_count++;
        }
    }
    clock_t end = clock();
    double sscanf_time = (double)(end - start) / CLOCKS_PER_SEC;
    printf("sscanf 方式耗时: %.6f 秒\n", sscanf_time);
    printf("sscanf 方式失败次数: %d\n", sscanf_fail_count);

    // 测试 inet_aton 方式
    start = clock();
    for (int i = 0; i < TEST_COUNT; i++) {
        if (!parse_ip_inet_aton(ip_array[i], &a, &b, &c, &d)) {
            inet_aton_fail_count++;
        }
    }
    end = clock();
    double inet_aton_time = (double)(end - start) / CLOCKS_PER_SEC;
    printf("inet_aton 方式耗时: %.6f 秒\n", inet_aton_time);
    printf("inet_aton 方式失败次数: %d\n", inet_aton_fail_count);

    // 比较两种方式的效率
    if (sscanf_time < inet_aton_time) {
        printf("sscanf 方式更快,效率高出 %.2f 倍\n", inet_aton_time / sscanf_time);
    } else {
        printf("inet_aton 方式更快,效率高出 %.2f 倍\n", sscanf_time / inet_aton_time);
    }

    return 0;
}

/*
sscanf 方式耗时: 0.116505 秒
sscanf 方式失败次数: 0
inet_aton 方式耗时: 0.043936 秒
inet_aton 方式失败次数: 0
inet_aton 方式更快,效率高出 2.65 倍
*/
相关推荐
JovaZou1 小时前
[Python学习日记-75] 计算机基础与网络
开发语言·网络·python·网络协议·学习·tcp/ip·计算机网络
KeyPan2 小时前
【Ubuntu与Linux操作系统:十、C/C++编程】
linux·运维·服务器·c语言·c++·算法·ubuntu
fqbqrr4 小时前
2501d,d作者,炮打C语言!
c语言·d
我想学LINUX4 小时前
【2024年华为OD机试】 (C卷,100分)- 消消乐游戏(Java & JS & Python&C/C++)
java·c语言·javascript·c++·游戏·华为od
graceyun5 小时前
C语言初阶习题【23】输出数组的前5项之和
c语言·开发语言·算法
余识-5 小时前
16.C语言预处理指令详解:#define、#include、#ifdef 等高效用法
c语言·数据库
skywalk81635 小时前
C语言基本知识复习浓缩版:数组
c语言·数据结构·c++·算法
Xiao Xiangζั͡ޓއއ6 小时前
于交错的路径间:分支结构与逻辑判断的思维协奏
c语言·开发语言·程序人生·学习方法·改行学it
Victoria.a7 小时前
数据在内存的存储
c语言·c++