Annex K 是技术名称。其他常见关键字是 __STDC_LIB_EXT1__ 和 __STDC_WANT_LIB_EXT1__。附件 K 定义了“安全”_s 后缀,例如 sprintf_s() 和 scanf_s()。
另请查看附录 K (2015) 的现场经验和边界检查 - cppreference.com 技术文档。
_s() 函数有什么意义?他们检查参数是否有更多不变量,例如“如果流为空、字符串为空、bufsz 为零或缓冲区写入超出指定长度的越界,则将调用约束处理程序”。这似乎是个好主意,对吧?是的!确实如此!
要点是你可以/可以这样做:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { printf_s("Hello %s!\n", "Alan Turing"); return 0; }
这与没有 __STDC_WANT_LIB_EXT1__ 的正常做事方式相比如何?
幸福之路
FILE *file = fopen("hello.txt", "r"); // file is OK.
FILE *file; errno_t err = fopen_s(&file, "hello.txt", "r"); // file is OK
悲伤之路
FILE *file = fopen("notexist.txt", "r"); // file is NULL, errno is set.
FILE *file; errno_t err = fopen_s(&file, "notexist.txt", "r"); // file is NULL, err is set.
坏路
FILE *file = fopen(NULL, NULL); // idk.
FILE *file; errno_t err = fopen_s(&file, NULL, NULL); // Constraint violated. Abort with message.
是的,您可以自定义约束处理程序以仅登录到文件并继续,就像什么都没发生一样。
set_constraint_handler_s(ignore_handler_s); set_constraint_handler_s(abort_handler_s); set_constraint_handler_s(my_awesome_handler);
注意到普通的 fopen() 如何具有相同的返回值(可能不同的 errno)来指示不同级别的错误严重程度?这就是 fopen_s() 试图改进的地方。至少,这是我读到的。我认为它就像 Rust 的panic!() 与返回的 Result
char* gets( char* str ); // (removed in C11) char* gets_s( char* str, rsize_t n ); // (since C11, annex K)登录后复制将 stdin 读入 str 指向的字符数组中,直到找到换行符或发生文件结尾。在读入数组的最后一个字符之后立即写入一个空字符。换行符被丢弃,但不存储在缓冲区中。
gets() 函数不执行边界检查,因此该函数极易受到缓冲区溢出攻击。它不能安全使用(除非程序运行在限制 stdin 上显示内容的环境中)。因此,该函数在 C99 标准的第三次勘误中已被弃用,并在 C11 标准中被完全删除。 fgets() 和 gets_s() 是推荐的替代品。
警告:切勿使用 gets()。
// BAD char buffer[1000]; gets(buffer); // ⚠️ Could write >1000 chars to `buffer`!
// GOOD char buffer[1000]; gets_s(buffer, sizeof(buffer)); // This will stop at 1000 chars.
_s() 函数似乎非常适合阻止可能发生缓冲区溢出的常见位置。
它们并没有在所有地方实现。 _s() 函数是一个扩展,在 GNU 的 glibc 等 libc 实现中不可用。还有其他一些小问题,比如它对于多线程来说不符合人体工程学,以及对于 strcpy_s() 之类的东西使用 sizeof(src) 而不是 sizeof(dest) 的常见错误,但与可用性问题相比,所有这些都显得苍白无力。
我能找到的大多数在线信息似乎表明 MSVC 是唯一实现了附件 K 的主要编译器/libc。
鉴于这些花哨的 _s() 函数并不存在于您的代码需要编译的所有地方,您需要编写如下代码:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { printf_s("Hello %s!\n", "Alan Turing"); return 0; }
...对于您想要执行 strlen_s() 或 fopen_s() 或 strcpy_s() 的每个实例。这是发疯的好方法。
很明显,你不会编写依赖于平台的代码只是为了执行基本的 printf() 和 strcpy() 但是将所有 #ifdef __STDC_LIB_EXT1__ #else 内容包装在库中怎么样?
我通过 Google 快速搜索发现了两个看起来很有前途的库:
所以...如果您想(或安全人员要求)使用 _s() 函数,但又不想将自己限制为 MSVC,那么您可以使用其中一个 ☝ 库。
?如需了解更多信息,请参阅附录 K (2015) 的现场经验和边界检查 - cppreference.com 技术文档。
以上是TIL CANnex K 存在,但您不应该使用它的详细内容。更多信息请关注PHP中文网其他相关文章!