C語言安全函數分享

????????在日常寫程序中有一些功能函數是可以重復使用的,在c語言的標準庫里面也有對應的功能函數,但是那些功能函數有會有小問題然后我就整理了一下對應功能的安全函數的使用。其中前四個函數可以編譯成一個動態庫,然后在項目工程中只需要包含對應的頭文件然后就可以調用了。

1:strcmp_iot()

????????在c語言標準庫中用于比較兩個字符串是否相等提供的函數為:strcmp()函數,還有它的衍生函數strncmp()等。

strcmp()函數的函數原型為:

#include <string.h>
int strcmp(const char *s1, const char *s2);

????????其核心原理是按照ASCII值逐字比較兩個字符串,然后根據返回值確定連個字符串是否相等。當返回值為0表示兩個字符串相等,<0表示S1小于S2,>0表示S1大于S2。

隱藏風險:

1:當傳遞的參數為NULL空指針的時候使用這個函數會直接出現段錯誤進而程序崩潰。

2:判斷字符的結束的標志位為'\0',如果傳遞過來的不是以'\0'結尾,可能會出現越界的風險。

3:strcmp 本身不寫入內存,但如果比較的是一個被溢出破壞的字符串,結果不可靠。

4:區分大小寫。

????????雖然strncmp函數比較與strcmp函數具有一定的優化和安全性,但是在實際使用中也會受到'\0'的影響,所以在這里給出一個全新的安全比較函數strcmp_iot();

函數原型:

#include <stddef.h>  // for size_t
#include <string.h>  // for strlen
/*** 安全比較兩個字符串是否相等* * @param string1 第一個字符串指針* @param string2 第二個字符串指針* @return 0 表示兩個字符串相同;1 表示不同或任一為 NULL*/
int strcmp_iot(const char *string1, const char *string2)
{// 檢查空指針if (string1 == NULL || string2 == NULL) {return 1;  // 認為不同}size_t len1 = strlen(string1);size_t len2 = strlen(string2);// 長度不同,直接返回不同if (len1 != len2) {return 1;}// 恒定時間比較,防止時序攻擊int result = 0;for (size_t i = 0; i < len1; i++) {result |= string1[i] ^ string2[i];  // 異或:相同為0,不同為非0}// 如果 result 為 0,說明所有字符都相同return result != 0;
}

這個函數的優點:

1:加上了空指針防護

2:采用長度檢查

3:恒定時間比較,防時序攻擊

4:可以在IOT設備的設備密鑰、Token、驗證碼、身份驗證、比對數據中廣泛使用,更安全。

2:strcpy_iot()

在傳統的c語言標準庫里面提供的復制函數分為兩類函數:1.字符串復制函數,2:內存復制函數。

函數是否檢查長度是否自動補?\0適用場景
strcpy? 否? 是已知目標足夠大(不推薦)
strncpy? 是? 否(需手動)安全字符串復制
memcpy? 是? 否任意內存塊復制
memmove? 是? 否支持內存重疊的復制

????????在程序員的實踐中有句話叫永遠不要使用strcpy函數,其他的幾個函數想要實現安全的復制函數最優解就是組合使用,我給到一個封裝好的安全的復制函數。

函數原型:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>/*** @brief 安全復制字符串到目標緩沖區* * @param dest      目標緩沖區* @param dest_size 目標緩沖區總大小(字節)* @param src       源字符串* @return int      0 = 成功, -1 = 失敗(如空指針或緩沖區太小)*/
int strcpy_iot(char *dest, size_t dest_size, const char *src)
{// 檢查空指針if (dest == NULL || src == NULL) {return -1;}// 檢查緩沖區大小if (dest_size == 0) {return -1;}// 使用 snprintf 進行安全復制// 返回值是“如果不截斷應寫入的字符數”int ret = snprintf(dest, dest_size, "%s", src);// 如果返回值 >= dest_size,說明被截斷了if (ret < 0) {// 編碼錯誤dest[0] = '\0';return -1;}if ((size_t)ret >= dest_size) {// 被截斷,可以視為失敗,或僅警告// 這里我們清空并返回失敗(嚴格模式)dest[0] = '\0';return -1;}return 0; // 成功
}

優點:

  • ? 防空指針
  • ? 防緩沖區溢出
  • ? 自動補?\0
  • ? 返回成功/失敗狀態
  • ? 使用?snprintf(推薦的安全方式)
  • ? 支持跨平臺

3:strstr_iot()

????????strstr是C 標準庫函數中用于字符串查找函數,用于在一個字符串中查找另一個子字符串的首次出現位置。其中還有一些衍生的函數:

函數用途
strstr(h, n)查找子字符串
strchr(s, c)查找單個字符
strrchr(s, c)查找字符最后一次出現
strcasestr(h, n)忽略大小寫的?strstr(Linux)

直接使用strstr函數的話可能出現的問題有:

1:傳遞的參數為空指針而導致的段錯誤。

2:區分大小寫,容易漏匹配

3:返回的是指針,容易誤用或越界訪問

4:無法處理重疊或二進制數據中的非字符串

????????基于上面可能會出現的問題給出兩個分裝函數用于解決上面的問題:

函數原型:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>/*** @brief 安全查找子字符串(區分大小寫)* * @param haystack 主字符串(被搜索的)* @param needle   子字符串(要找的)* @return char*   匹配位置指針,未找到返回 NULL*/
const char* strstr_iot(const char *haystack, const char *needle)
{// ? 空指針檢查if (haystack == NULL) {return NULL;}if (needle == NULL) {return NULL;}// ? 空字符串處理:strstr 標準行為是返回 haystackif (needle[0] == '\0') {return haystack;}// ? 調用標準庫return strstr(haystack, needle);
}

忽略大小寫的版本(跨平臺)

/*** @brief 安全忽略大小寫的字符串查找(跨平臺)* * @param haystack 主字符串* @param needle   子字符串* @return const char* 匹配位置,未找到返回 NULL*/
const char* strcasestr_iot(const char *haystack, const char *needle)
{if (haystack == NULL || needle == NULL) {return NULL;}if (needle[0] == '\0') {return haystack;}size_t needle_len = strlen(needle);for (const char *p = haystack; *p != '\0'; p++) {const char *h = p;const char *n = needle;while (*h && *n && (tolower(*h) == tolower(*n))) {h++;n++;}if (*n == '\0') {return p; // 找到了}}return NULL; // 未找到
}

4:atoi_iot()

在c語言中將字符串轉換為整數的標準函數,雖然操作簡單但是存在巨大的安全隱患,我在初期寫程序中就被這個擺了一道,也是沒有注意其中出現的風險。

缺點:

1:atoi函數的轉喊成功與失敗的依據是函數的返回值,但是在使用中如果轉換的數據是字符0,那就會混淆轉換結果。

int b = atoi("0");    // → 0   ?
int c = atoi("xyz");  // → 0   ? 但你怎么知道是失敗了?

2:函數使用的是int類型,當超出int范圍會出現未定義現象。

3:如果傳入的數據是空指針或者空字符串就直接觸發段錯誤從而程序崩潰。

因此根據上面出現的問題,也給出相應的替代函數strtol(字符串轉 long)是 atoi?的安全替換函數,我在此基礎之上再進行封裝。

函數原型:

#include <stdlib.h>
#include <errno.h>
#include <limits.h>/*** @brief 安全字符串轉整數* * @param str 輸入字符串* @param result 輸出的整數值* @return int 0 = 成功, -1 = 失敗*/
int atoi_iot(const char *str, int *result)
{// 檢查空指針if (str == NULL || result == NULL) {return -1;}// 跳過前導空白(可選)while (*str == ' ' || *str == '\t') str++;// 空字符串if (*str == '\0') {return -1;}char *endptr;errno = 0;long val = strtol(str, &endptr, 10);// 檢查是否完全沒有轉換if (endptr == str) {return -1; // 無有效數字}// 檢查是否轉換了整個字符串while (*endptr == ' ' || *endptr == '\t') endptr++;if (*endptr != '\0') {return -1; // 后面有非法字符}// 檢查溢出if (errno == ERANGE || val < INT_MIN || val > INT_MAX) {return -1;}*result = (int)val;return 0;
}

最后分享一個linux系統的主函數參數解析函數

5:getopt()

在我前期的寫程序中對于主函數傳參的處理就是簡單的調用,后面設計到傳遞的參數過多就顯得很麻煩了,然后我就發現了原來還有一個主函數傳參的高級用法getopt()。

函數原型:

int getopt(int argc, char *const argv[], const char *optstring);

參數?? ?含義
argc?? ?命令行參數個數(main 函數傳入)
argv?? ?命令行參數數組(main 函數傳入)
optstring?? ?定義合法選項的字符串
optstring 的格式
每個字符代表一個有效的命令行選項。
如果某個選項需要參數(比如 -d /dev/lirc0 中的 /dev/lirc0),就在字符后加一個冒號 :。
示例:
"d:f:h"
表示:
-d 后面必須跟一個參數(如設備路徑)
-f 后面必須跟一個參數(如配置文件路徑)
-h 是一個開關型選項,不需要參數

程序舉例:

#include <unistd.h>
#include <stdio.h>int main(int argc, char *argv[])
{int opt;while ((opt = getopt(argc, argv, "i:o:v")) != -1) {switch (opt) {case 'i':printf("輸入文件: %s\n", optarg);break;case 'o':printf("輸出文件: %s\n", optarg);break;case 'v':printf("啟用詳細模式\n");break;default:fprintf(stderr, "用法: %s -i input -o output [-v]\n", argv[0]);return 1;}}return 0;
}

主函數運行傳遞的參數為:

./app -i input.txt -o output.txt -v

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96260.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96260.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96260.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

汽車之家聯合HarmonyOS SDK,深度構建鴻蒙生態體系

汽車之家作為一家領先的汽車互聯網公司&#xff0c;致力于打造服務全球的汽車生態科技平臺&#xff0c;覆蓋"看選買用換"的一站式購車體驗。2023年12月底&#xff0c;汽車之家正式啟動鴻蒙開發&#xff0c;并于2024年年底成功構建了完整的鴻蒙生態體系&#xff0c;涵…

深度學習驅動的訂單簿分析與交易策略優化

訂單簿數據特征與預處理方法 高頻金融數據中&#xff0c;訂單簿&#xff08;Order Book&#xff09;承載著市場參與者的實時交易意圖。不同于K線數據的聚合特性&#xff0c;訂單簿數據具有獨特的時空特征&#xff1a; 多維層級結構&#xff1a;包含不同價格檔位的買賣盤深度信息…

Redis--day9--黑馬點評--分布式鎖(二)

&#xff08;以下所有內容全部來自上述課程&#xff09; 分布式鎖 1. Redisson功能介紹 基于setnx實現的分布式鎖存在下面的問題&#xff1a; 不可重入&#xff1a;同一個線程無法多次獲取同一把鎖不可重試&#xff1a;獲取鎖只嘗試一次就返回false&#xff0c;沒有重試機…

ES入門教程 (python 版)

ES入門教程 1. 創建ES對象from elasticsearch import Elasticsearch # 實例化一個ip為localhost&#xff0c;端口為9200&#xff0c;允許超時一小時的es對象 es Elasticsearch(hosts"localhost",port9200,timeout3600) # 1. 創建 索引 index_name "test"…

Gateway中Forward配置+源碼觀賞

系列文章目錄 文章目錄系列文章目錄一、ForwardPathFilter二、RouteToRequestUrlFilter三、ForwardRoutingFilteryaml forward配置gateway:routes:- id: user-route # uri: lb://useruri: forward:///user/indexpredicates:- Path/user/**- YoGET # filt…

BAS16XV2T1G ON安森美半導體 高速開關二極管 電子元器件IC

BAS16XV2T1G ON Semiconductor 高速開關二極管專業解析1. 產品技術檔案BAS16XV2T1G是安森美半導體(ON Semiconductor)推出的高速開關二極管&#xff0c;采用SOT-523超微型封裝&#xff08;1.60.80.95mm&#xff09;&#xff0c;專為現代高密度電子設備設計&#xff0c;以其超快…

親測可用 [安卓]《神秘來電》V1.1無需登入無廣告離線打開即用手機模擬發起虛假來電免費版

神秘來電是一款可以模擬虛擬電話的應用程序&#xff0c;它能夠在用戶需要的時候模擬各種來電&#xff0c;以便用戶能夠在尷尬的場合脫身。用戶可以預設多個不同的來電號碼和鈴聲&#xff0c;并可隨時觸發這些虛擬電話&#xff0c;在特殊情況下幫助用戶擺脫尷尬。它為那些社交恐…

8.20 dp

lc73矩陣置零queue隊列標記// 整行置零for(int y0; y<n; y) matrix[i][y] 0; // 整列置零for(int x0; x<m; x) matrix[x][j] 0; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int m matrix.size(), n matrix[0].size();//…

STL庫——string(類模擬實現)

? ? ? ? ? づ?ど &#x1f389; 歡迎點贊支持&#x1f389; 個人主頁&#xff1a;勵志不掉頭發的內向程序員&#xff1b; 專欄主頁&#xff1a;C語言&#xff1b; 文章目錄 前言 一、基本框架 二、構造函數 三、析構函數 四、拷貝構造 五、運算符重載 5.1、賦值重載 5.2…

Linux I/O 多路復用實戰:深入剖析 Select 與 Poll

## 引言:從“阻塞”的餐廳到“事件驅動”的盛宴 想象一下,你是一家小餐館的服務員。餐廳只有5張桌子。你的工作流程是這樣的:走到1號桌,問他們是否要點菜,然后站在那里等他們決定;等他們點完,再去2號桌,同樣站在那里等... 如果1號桌的客人看菜單看了半個小時,那么其他…

【clion】cmake腳本1:調試腳本并構建Fargo項目win32版本

調試腳本并構建 【clion】visual studio的sln轉cmakelist并使用clion構建32位 報錯 "D:\Program Files\JetBrains\CLion 2022.3.1\bin\cmake\win\x64\bin\cmake.exe" --debugger --debugger-pipe=\\<

VS2005里的快捷鍵

VS2005是微軟在2005發布的一款支持C、C#、.net開發語言的集成開發工具&#xff0c;它支持的C版本為C03&#xff0c;但不支持C11&#xff0c;到VS2013才支持大部分的C11(簡稱C11)&#xff0c;到VS2015 update3才完全支持C11。既然VS2005不支持C11&#xff0c;而智能指針是C11才引…

前后端聯合實現文件下載,實現 SQL Server image 類型文件下載

1、前端 Vue3QualityFile.vue<script setup lang"ts" name"QualityFile"> ...... // 下載&#xff0c;實現 SQL Server image 類型文件下載 const onDownloadClick async (fileNo: string) > {// const result await qualityFileDownloadFileWi…

【OneAI】使用Rust構建的輕量AI網關

LLM網關 統一大模型API入口&#xff0c;使用一個令牌調用多家模型&#xff0c;無需切換API Key兼容OpenAI輸入輸出規范內置10提供商和50模型&#xff0c;開箱即用支持自動負載、限流、IP限制、Token用量限制等功能支持釘釘、飛書、企微消息預警支持對不同提供商設置代理支持主…

Jenkins服務器配置SSH

1. 創建Jenkins用戶的SSH配置ssh-keygen -t rsa -b 4096 -f /tmp/jenkins_ssh_key -N ""2. 在Jenkins服務器上執行以下命令# 切換到root用戶 sudo su -# 創建Jenkins用戶的SSH目錄 mkdir -p /var/lib/jenkins/.ssh chown jenkins:jenkins /var/lib/jenkins/.ssh chmo…

nginx-下載功能-狀態統計-訪問控制

nginx-下載功能-狀態統計-訪問控制一、利用nginx做網站提供下載功能1. 進入nginx存放配置文件目錄2. 編輯nginx.conf文件&#xff0c;開啟下載功能3. 檢查nginx.conf主配置文件是否正確4. 重啟nginx服務5. 修改首頁文件index.html6. 訪問首頁7. 去網頁根目錄下新建download目錄…

GitLab CI/CD、Jenkins與GitHub Actions在Kubernetes環境中的方案對比分析

GitLab CI/CD、Jenkins與GitHub Actions在Kubernetes環境中的方案對比分析 隨著容器化和微服務的普及&#xff0c;基于Kubernetes的部署已經成為主流。在實際的生產環境中&#xff0c;如何選擇合適的CI/CD流水線方案以實現自動化構建、測試、部署和發布&#xff0c;直接關系到團…

tcp會無限次重傳嗎

tcp作為面向連接的&#xff0c;可靠的&#xff0c;字節流。最重要的特點就是可靠&#xff0c;其中重傳又是保證可靠的重要前提。那么當tcp發送數據之后&#xff0c;收不到ack的情況下&#xff0c;會無限次重傳嗎。不會。# cat /proc/sys/net/ipv4/tcp_retries1 3 # cat /proc/s…

EasyAIoT平臺部署

EasyAIoT官方文檔專注于 AIoT 智能硬件與工業軟件解決方案&#xff0c;提供從設備接入到云端管理的全棧服務http://pro.basiclab.top:9988/

功能測試相關問題

1.功能測試流程&#xff08;工作流程&#xff09;需求分析 -- 測試點分析&#xff08;xmind&#xff09;-- 編寫測試計劃/用例及評審 -- 執行測試用例&#xff08;開發提交測試&#xff09;-- 發現缺陷通過缺陷管理工具提交 -- 回歸測試及bug驗證&#xff08;開發提測新版本&am…