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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…