C11 中具有安全边界检查的函数
前言
我记得最早加入安全边界检查函数的是微软,在一些涉及缓冲区的基本 C 函数中,一律加上了 _s
后缀的、具有安全边界检查功能的函数。有少部分与之前微软定义的不兼容,这里以 C11 标准为准。
C11 标准引入了这些函数,它们比之前习惯性使用的传统函数更加安全,可以防止出现缓冲区溢出问题错误的发生。但是,能不能做到真正安全,还是需要编码者更细心地正确去编码。
不可理喻的是,C11 标准居然把这些定义的标准设置为可选。既然是标准,就应该是必须实现的才对嘛。这个让使用者情何以堪,到底我们使用它还是不用它 ??
如何确定编译器是否支持安全边界检查函数
如果编译器的标准库实现了安全边界检查函数,就会定义 __STDC_LIB_EXT1__
的宏。
1 |
|
如何开启使用安全边界检查函数
好奇葩的一点,如果你想使用安全边界检查函数,还要相应的在 #include 头文件之前定义一个宏 __STDC_WANT_LIB_EXT1__
的值为 1,才能开启使用这个头文件中的安全边界检查函数。
举例,string.h 里面定义了一些安全边界检查函数,如果要使用它,就需要按照如下的写法:
1 |
|
strlen_s
strlen_s 是 strlen 的安全版本,用于返回字符串的长度。原型:
1 | size_t strnlen_s(const char *str, size_t strsz); |
第一个参数 str 为字符串指针,第二个参数为缓冲区大小,如果字符串超出缓冲区大小还没有以 \0 结尾则返回缓冲区大小。
strcpy_s
strcpy_s 是 strcpy 的安全版本,用于复制字符串。原型:
1 | errno_t strcpy_s(char *restrict dest, rsize_t destsz, const char *restrict src); |
第二个参数指出目标缓冲区 dest 的大小。复制成功,返回 0;失败则返回非 0 。
strncpy_s
strncpy_s 是 strncpy 的安全版本,用于复制字符串。原型:
1 | errno_t strncpy_s(char *restrict dest, rsize_t destsz, |
第二个参数指出目标缓冲区 dest 的大小。第四个参数指出最多从 src 复制多少个字符。如果前 count 个字符中没有 \0,会继续把 \0 添加的目标字符串后面。复制成功,返回 0;失败则返回非 0 。
strcat_s
strcat_s 是 strcat 的安全版本,用于追加复制字符串。原型:
1 | errno_t strcat_s(char *restrict dest, rsize_t destsz, const char *restrict src); |
第二个参数指出目标缓冲区 dest 的大小。
strncat_s
strncat_s 是 strncat 的安全版本,用于追加复制字符串。原型:
1 | errno_t strncat_s(char *restrict dest, rsize_t destsz, |
第二个参数指出目标缓冲区 dest 的大小。第四个参数指出最多从 src 追加复制多少个字符。如果前 count 个字符中没有 \0,会继续把 \0 添加的目标字符串后面。复制成功,返回 0;失败则返回非 0 。
gets_s
从stdin流中读取字符串,直至接受到换行符或EOF时停止,并将读取的结果存放在 str 指针所指向的字符数组中。原型:
1 | char *gets_s( char *str, rsize_t n ); |
第二个参数指出目标缓冲区 str 的大小。
strtok_s
将字符串进行单元化,分割转换为一系列 token。(这个函数跟微软的不一样)
1 | char *strtok_s(char *restrict str, rsize_t *restrict strmax, |
- str : 需要被分割的字符串。执行第一次分割之后,对同一个字符串执行后续的分割时,这个参数是 NULL。
- strmax : 指向一个 rsize_t 的整数,这个整数表示需要分割的字符串的长度。每次调用 strtok_s 之后,函数会更新这个整数值,表示分割后剩余的字符数。
- delim : 包含所有可能分界的字符的字符串。
- ptr : 指向 char* 类型的变量的指针。函数在该变量中存储信息,允许在找到第一个 token 之后继续搜索标记。
返回值:
返回分割的 token,如果没有,返回 NULL。