C/C 编程不可避免地会面对内存越界引发的问题,不同的公司也会出台相应的编码规范提前对内存越界进行规避,但不管怎么说,如果想要彻底解决内存越界就要求大家养成好的编程习惯从根本上解决内存越界问题。
一 使用安全的库函数
- strncpy代替strcpy,定义如下:
#include <string.h>
char *strncpy(char *dest, const char *src, int n)
上面的定义表示表示把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回被复制后的dest。复制结束时会自动在字符串的末尾加上结束符因此拷贝n个字符时需要开辟n 1个空间。具体实例如下:
代码语言:javascript复制int main(){
char name[]={"hello world"},destin[20]={};
strncpy(destin,name,6);
printf("%sn",destin);
}
- snprintf代替sprint,定义如下:
int snprintf(char *str, size_t size, const char *format, ...)
将可变参数 “…” 按照format的格式格式化为字符串,然后再将其拷贝至str中。实际使用时建议将sprint全部使用安全函数进行替换,避免引入不必要的内存溢出问题。使用实例如下:
代码语言:javascript复制int main(){
if (!bHaveRecs){
snprintf(m_szErrorMsg,ERROR_MSG_LEN,"There is no data in PDB ! Table=[%s] KeyInfo = [%s]",
pszTableName,pszKeyInfo);
return ERROR_NO_DATA_IN_ORACLE;
}
}
- 使用fgets代替gets,定义如下:
#include <stdio.h>
char *fgets(char *str, int n, FILE *stream)
翻开源码可知gets函数不会检查缓冲区的大小,反之fgets会通过第二个参数对拷贝的字符串进行限制,最多会拷贝n-1个字符并且在拷贝字符串的结尾主动加上结束符,因此在实际的编程时尽量使用fgets,以增强代码的健壮性。具体使用如下:
代码语言:javascript复制if (fgets(l_ret, 1024, fp) == NULL)
{
pclose(fp);
return RET_OK;
}
- strncat代替strcat,定义如下:
#include <stdio.h>
char * strncat(char *dest, const char *src, size_t n)
和strncpy一样,拷贝n个字符到dest中,并且在拷贝结束时自动加上结束符标识,实际使用时需要注意,拷贝缓冲区的大小需要预留一位给结束符。如果需要拷贝n个字符则需要申请n 1个空间大小。编码如下:
代码语言:javascript复制if( (i & kMlsOptPerm) != 0)
{
strncat(sOption, "perm;", min(sizeof("perm;"), sizeof(sOption)-strlen(sOption)-1) );
}
二 使用宏定义
在代码中使用宏定义可以确保缓冲区的大小和需要复制的字符串的大小同步修改,从而保证长度定义的一致性。
sizeof也是一个宏,编码时经常用到,如下面的代码:
代码语言:javascript复制 int main(){
char pc[20]={"abc"};
printf("%lu",sizeof(pc));
}
如上代码输出结果为:20;
同样,也可以对上述代码进行优化,即使用宏来表示常量20.如下代码所示:
代码语言:javascript复制#define SHORT_CHAR_SIZE (20)
int main(){
char pc[SHORT_CHAR_SIZE]={"abc"};
printf("%lu",sizeof(pc));
}
如此,在一些代码体量比较大的项目中,可以在一个地方定义系列宏以方便后期对字符串大小进行扩充改造。
总之,在目前的C/C 库中,安全函数和非安全函数都进行了保留,在实际的编码中,大家尽量选择安全的库函数进行使用。
- EOF -
推荐阅读 点击标题可跳转
1、C 20新特性(十三)—约束和概念(上)
2、28 张图,一次性说清楚 TCP
3、C 20新特性(十二)—编程中常用的几个新特性