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

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

这里用两种方式:

  1. sscanf格式化处理
  2. 用 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 倍
*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/950811.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

arcgisPro加载CGCS2000天地图后,如何转成米单位

1、导入加载的天地图影像服务&#xff0c;一开始是经纬度显示的。 2、右键地图&#xff0c;选择需要调整的投影坐标&#xff0c;这里选择坐标如下&#xff1a; 3、点击确定后&#xff0c;就可以调整成米单位的了。 4、切换后结果如下&#xff1a; 如有需要&#xff0c;可调整成…

新时期下k8s 网络插件calico 安装

1、k8s master节点初始化完毕以后一直处于notreadey状态&#xff0c;一直怀疑是安装有问题或者是初始化有问题&#xff08;当然&#xff0c;如果真有问题要先解决这些问题&#xff09;&#xff0c;经过不断探索才发现是网络插件没有安装导致的&#xff0c;根据建议安装calico插…

《分布式光纤测温:解锁楼宇安全的 “高精度密码”》

在楼宇建筑中&#xff0c;因其内部空间庞大&#xff0c;各类电器设施众多&#xff0c;如何以一种既高效又稳定&#xff0c;兼具低成本与高覆盖特性的方式&#xff0c;为那些关键线路节点开展温度监测&#xff0c;是目前在安全监测领域一项重点研究项目&#xff0c;而无锡布里渊…

基于vue框架的的校园社团管理平台9ck4e(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;社团,社团加入,学生,社团活动,活动报名,社团成员,物资信息,物资申请 开题报告内容 基于Vue框架的校园社团管理平台开题报告 一、研究背景与意义 随着信息化技术的快速发展&#xff0c;校园管理正逐步向数字化、智能化转型。校园社团作…

网络安全 基础入门-概念名词

域名相关 域名 域名和IP地址相互映射&#xff0c;这样不用去记住能够被机器直接读取的IP地址数串 域名系统(DNS) 它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网。DNS使用UDP端口53。 1. 如果是自动获取dns,就向上查询&#xff…

CSS Grid 布局全攻略:从基础到进阶

文章目录 一.Grid 是什么二.示例代码1. 基础使用 - 固定宽高2.百分百宽高3.重复设置-repeat4.单位-fr5.自适应6.间距定义其他 一.Grid 是什么 CSS 中 Grid 是一种强大的布局方式&#xff0c;它可以同时处理行和列 Grid 和Flex有一些类似&#xff0c;都是由父元素包裹子元素使用…

自动驾驶控制算法-油门刹车标定

本文是学习自动驾驶控制算法第十讲 油门刹车标定表的制作以及后续一节的学习笔记。 车辆油门刹车标定的目的是获取不同车速下不同的油门踏板或刹车踏板行程下车辆的加速度&#xff0c;标定的结果作为纵向控制模型的输入&#xff0c;用于计算输出合理的油门或刹车。 1 Apollo中…

2024年1月4日蜻蜓hr人才招聘系统v1.1.7更新-正式版发布-客户端源代码开源发布供学习-本产品完成上线正式版-修复多个bug-优雅草果果|小无

2024年1月4日蜻蜓hr人才招聘系统v1.1.7更新-正式版发布-客户端源代码开源发布供学习-本产品完成上线正式版-修复多个bug-优雅草果果|小无 前端代码开源库 关于开源说明&#xff1a;企业服务-招聘信息管理系统-前端uniapp-系统前端开放源代码仅供学习-优雅草科技-目前优雅草科…

Java-JVM详解

Java-JVM ①JVM概述 ❶基本介绍 JVM&#xff1a;全称 Java Virtual Machine&#xff0c;一个虚拟计算机&#xff0c;Java 程序的运行环境&#xff08;Java二进制字节码的运行环境&#xff09; 特点&#xff1a; Java 虚拟机基于二进制字节码执行&#xff0c;由一套字节码指…

PyTorch 框架实现线性回归:从数据预处理到模型训练全流程

系列文章目录 01-PyTorch新手必看&#xff1a;张量是什么&#xff1f;5 分钟教你快速创建张量&#xff01; 02-张量运算真简单&#xff01;PyTorch 数值计算操作完全指南 03-Numpy 还是 PyTorch&#xff1f;张量与 Numpy 的神奇转换技巧 04-揭秘数据处理神器&#xff1a;PyTor…

升级 Spring Boot 3 配置讲解 —— 支持断点传输的文件上传和下载功能

学会这款 &#x1f525;全新设计的 Java 脚手架 &#xff0c;从此面试不再怕&#xff01; 在现代 Web 应用中&#xff0c;文件上传和下载是非常常见的需求。然而&#xff0c;当文件较大时&#xff0c;传统的上传下载方式可能会遇到网络不稳定或传输中断的问题。为了解决这些问题…

R语言安装教程与常见问题

生物信息基础入门笔记 R语言安装教程与常见问题 今天和大家聊一个非常基础但是很重要的技术问题——如何在不同操作系统上安装R语言&#xff1f;作为生物信息学数据分析的神兵利器&#xff0c;R语言的安装可谓是入门第一步&#xff0c;学术打工人的必备技能。今天分享在Windows…

UI自动化测试保姆级教程--pytest详解(精简易懂)

欢迎来到啊妮莫的学习小屋 别让过去的悲伤&#xff0c;毁掉当下的快乐一《借东西的小人阿莉埃蒂》 简介 pytest是一个用于Python的测试框架, 支持简单的单元测试和复杂的功能测试. 和Python自带的UnitTest框架类似, 但是相比于UnitTest更加简洁, 效率更高. 特点 非常容易上手…

基类指针指向派生类对象,基类指针的首地址永远指向子类从基类继承的基类首地址

文章目录 基类指针指向派生类对象&#xff0c;基类指针的首地址永远指向子类从基类继承的基类起始地址。代码代码2 基类指针指向派生类对象&#xff0c;基类指针的首地址永远指向子类从基类继承的基类起始地址。 代码 #include <iostream> using namespace std;class b…

分布式Id方案选择

分布式 ID 方案选择 在当今分布式系统日益盛行的背景下&#xff0c;分布式 ID 生成方案的选择成为了众多开发者关注的焦点。一个优秀的分布式 ID 方案&#xff0c;不仅能够确保生成的 ID 全局唯一&#xff0c;避免数据冲突&#xff0c;还能在高并发、大规模的分布式环境中保持…

花生好坏缺陷识别数据集,7262张图片,支持yolo,coco json,pasical voc xml格式的标注,识别准确率在95.7%

花生好坏缺陷识别数据集,7262张图片&#xff0c;支持yolo&#xff0c;coco json&#xff0c;pasical voc xml格式的标注&#xff0c;识别准确率在95.7% 数据集分割 训练组87&#xff05; 6353图片 有效集8% 606图片 测试集4% 303图片 预处理 自动定…

springboot 集成 etcd

springboot 集成 etcd 往期内容 ETCD 简介docker部署ETCD 前言 好久不见各位小伙伴们&#xff0c;上两期内容中&#xff0c;我们对于分布式kv存储中间件有了简单的认识&#xff0c;完成了docker-compose 部署etcd集群以及可视化工具 etcd Keeper&#xff0c;既然有了认识&a…

【递归与分治】Leetcode23:合并K个升序链表

一、题目描述 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]] 输出&#xff1a;[1,1,2,3,4,4,5,6] 解释&#xff1a;链表数…

将分支A某一个commit合并到分支B

1.寻找A分支的commit 在分支B下&#xff0c;点击git找到分支A的历史提交记录,如图所示&#xff1a; 2.点击分支A的某个commit&#xff0c;进行合并到分支B 将这个commit&#xff0c;进行cherry-Pick&#xff0c;就可以把分支A的合并到分支B上的本地仓库中&#xff0c;然后就可…

如何快速上手一个鸿蒙工程

作为一名鸿蒙程序猿&#xff0c;当你换了一家公司&#xff0c;或者被交接了一个已有的业务。前辈在找你之前十分钟写了一个他都看不懂的交接文档&#xff0c;然后把一个鸿蒙工程交接给你了&#xff0c;说以后就是你负责了。之后几天你的状态大概就是下边这样的&#xff0c;一堆…