最近在做lldp的snmp返回值时需要做这样的转换处理:C语言将点分十进制的IP字符串转成4个整数。
这里用两种方式:
- sscanf格式化处理
- 用 inet_aton函数将ip字符串转成32位的整形,然后再根据bit转成对应的4个整数。
- man命令可以确认下sscanf和inet_aton的返回值,以确认处理成功还是失败。
- 字节序问题:inet_aton后统一用网络字节序,避免出错。
sscanf
#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
#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字符串,然后再跑下测试。
#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随机生成一百万次,测试:
#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 倍
*/