利用C語言將點(diǎn)分十進(jìn)制的IP字符串轉(zhuǎn)成4個(gè)整數(shù)
最近在做lldp的snmp返回值時(shí)需要做這樣的轉(zhuǎn)換處理:C語言將點(diǎn)分十進(jìn)制的IP字符串轉(zhuǎn)成4個(gè)整數(shù)。
這里用兩種方式:
1.sscanf格式化處理
2.用 inet_aton函數(shù)將ip字符串轉(zhuǎn)成32位的整形,然后再根據(jù)bit轉(zhuǎn)成對應(yīng)的4個(gè)整數(shù)。
man命令可以確認(rèn)下sscanf和inet_aton的返回值,以確認(rèn)處理成功還是失敗。
字節(jié)序問題:inet_aton后統(tǒng)一用網(wǎng)絡(luò)字節(jié)序,避免出錯(cuò)。
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() { // 定義點(diǎn)分十進(jìn)制的 IP 字符串 const char *ip_str = "192.168.1.1"; // 定義變量存儲(chǔ)解析結(jié)果 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() { // 定義點(diǎn)分十進(jìn)制的 IP 字符串 const char *ip_str = "192.168.1.1"; // 定義變量存儲(chǔ)解析結(jié)果 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; }
哪個(gè)效率高點(diǎn)?
這里用的是固定的字符串跑的測試,不太嚴(yán)謹(jǐn)。。??梢钥紤]隨機(jī)生成1~255的數(shù)字組成ip字符串,然后再跑下測試。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <time.h> #define TEST_COUNT 1000000 // 測試次數(shù) // 使用 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() { // 定義點(diǎn)分十進(jìn)制的 IP 字符串 const char *ip_str = "192.168.1.1"; // 定義變量存儲(chǔ)解析結(jié)果 int a, b, c, d; // 記錄失敗的次數(shù) 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 方式耗時(shí): %.6f 秒\n", sscanf_time); printf("sscanf 方式失敗次數(shù): %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 方式耗時(shí): %.6f 秒\n", inet_aton_time); printf("inet_aton 方式失敗次數(shù): %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 方式耗時(shí): 0.104025 秒 sscanf 方式失敗次數(shù): 0 inet_aton 方式耗時(shí): 0.027499 秒 inet_aton 方式失敗次數(shù): 0 inet_aton 方式更快,效率高出 3.78 倍 */
修改ip隨機(jī)生成一百萬次,測試:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <time.h> #define TEST_COUNT 1000000 // 測試次數(shù) // 生成一個(gè)隨機(jī)的合法 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() { // 初始化隨機(jī)數(shù)種子 srand(time(NULL)); // 定義變量存儲(chǔ)解析結(jié)果 int a, b, c, d; // 記錄失敗的次數(shù) int sscanf_fail_count = 0; int inet_aton_fail_count = 0; // 動(dòng)態(tài)分配堆空間存儲(chǔ) IP 地址數(shù)組 char (*ip_array)[16] = malloc(TEST_COUNT * sizeof(*ip_array)); if (ip_array == NULL) { printf("內(nèi)存分配失??!\n"); return 1; } // 隨機(jī)生成 IP 地址數(shù)組 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 方式耗時(shí): %.6f 秒\n", sscanf_time); printf("sscanf 方式失敗次數(shù): %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 方式耗時(shí): %.6f 秒\n", inet_aton_time); printf("inet_aton 方式失敗次數(shù): %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 方式耗時(shí): 0.116505 秒 sscanf 方式失敗次數(shù): 0 inet_aton 方式耗時(shí): 0.043936 秒 inet_aton 方式失敗次數(shù): 0 inet_aton 方式更快,效率高出 2.65 倍 */
以上就是利用C語言將點(diǎn)分十進(jìn)制的IP字符串轉(zhuǎn)成4個(gè)整數(shù)的詳細(xì)內(nèi)容,更多關(guān)于C語言IP字符串轉(zhuǎn)成4個(gè)整數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(38.計(jì)數(shù)和讀法)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(38.計(jì)數(shù)和讀法),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07c/c++ 標(biāo)準(zhǔn)庫 bind 函數(shù)詳解
bind是一組用于函數(shù)綁定的模板。在對某個(gè)函數(shù)進(jìn)行綁定時(shí),可以指定部分參數(shù)或全部參數(shù),也可以不指定任何參數(shù),還可以調(diào)整各個(gè)參數(shù)間的順序。這篇文章主要介紹了c/c++ 標(biāo)準(zhǔn)庫 bind 函數(shù) ,需要的朋友可以參考下2018-09-09C++11運(yùn)算符重載和向量類重載實(shí)例詳解(<<,>>,+,-,*等)
這篇文章主要給大家介紹了關(guān)于C++11運(yùn)算符重載和向量類重載的相關(guān)資料,主要包括<<,>>,+,-,*等,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-07-07C++實(shí)現(xiàn)LeetCode(20.驗(yàn)證括號(hào))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(20.驗(yàn)證括號(hào)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07如何判斷一個(gè)數(shù)是否為2的冪次方?若是,并判斷出來是多少次方?
本篇文章是對如何判斷一個(gè)數(shù)是否為2的冪次方?若是,并判斷出來是多少次方的實(shí)現(xiàn)方法,進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03Microsoft Visual C++ 6.0開發(fā)環(huán)境搭建教程
這篇文章主要為大家詳細(xì)介紹了Microsoft Visual C++ 6.0開發(fā)環(huán)境搭建教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04