strcpy_s在c++中能用但非跨平台:msvc原生支持,gcc/clang默认不提供;其安全机制依赖正确传入目标缓冲区大小,否则仍可能失效,推荐优先使用std::string等raii方案。

strcpy_s 在 C++ 中到底能不能用
能用,但不是所有编译器都默认支持,也不是所有标准库实现都提供。它属于 ISO/IEC TR 24731-1(C11 的可选扩展),在 MSVC 中原生支持且默认启用,在 GCC 和 Clang 中默认不提供 strcpy_s,需手动启用或换用替代方案。
这意味着:写跨平台代码时直接调用 strcpy_s 很可能在 Linux/macOS 下编译失败,报错 ‘strcpy_s’ was not declared in this scope。
MSVC 下怎么正确调用 strcpy_s
在 Visual Studio 中,strcpy_s 定义于 <cstring></cstring>,但必须满足两个前提:
- 定义宏
_CRT_SECURE_NO_WARNINGS(否则会因使用“不安全函数”警告而阻断编译) - 确保目标缓冲区大小传参正确——这是最常出错的地方
strcpy_s 原型是:errno_t strcpy_s(char* dst, rsize_t dstSize, const char* src)。注意第二参数是整个缓冲区字节数,不是字符串长度,也不是 sizeof(dst)(若 dst 是指针而非数组,sizeof 会返回指针大小)。
常见错误写法:
char buf[64]; strcpy_s(buf, sizeof(buf), "hello"); // ✅ 正确 strcpy_s(buf, 64, "hello"); // ✅ 也对,但易错(硬编码易脱节) char* p = new char[64]; strcpy_s(p, sizeof(p), "hello"); // ❌ 错!sizeof(p) 是 8(64 位指针大小) strcpy_s(p, 64, "hello"); // ✅ 正确,但需确保 64 是真实分配大小
GCC/Clang 下没有 strcpy_s 怎么办
别硬加头文件或自己声明——这会导致未定义行为。可行路径有三条:
- 用
std::string替代 C 风格字符串(推荐,尤其新项目) - 启用 GNU 扩展的
__builtin_strcpy+ 手动长度检查(不跨平台,且无运行时保护) - 用 POSIX 的
strlcpy(macOS/BSD 原生支持;Linux 需 glibc ≥ 2.39 或 musl,否则要自己实现)
例如用 strlcpy 替代:
char dst[32]; strlcpy(dst, "hello world", sizeof(dst)); // 自动截断并保证 null 终止 // 返回值是源字符串总长度(可能 > sizeof(dst)-1),可用于判断是否截断
注意:strlcpy 不是 C 标准函数,glibc 直到 2023 年底才正式加入,旧系统仍需兼容处理。
为什么 strcpy_s 比 strcpy 更“安全”,又为什么还不够安全
strcpy_s 在运行时检查 dstSize 是否为 0、src 是否为空指针、以及是否会发生溢出。溢出时返回 ERANGE 并清空目标缓冲区(部分实现),避免内存破坏。
但它无法解决这些根本问题:
- 开发者仍需手动传入正确
dstSize,传错就失去保护意义 - 不检查
src是否为合法 null 终止字符串(若src缺少 \0,行为未定义) - 不防止误用:比如把
dstSize写成strlen(src)+1,结果缓冲区不够大 - 多线程下不提供额外同步保障
真正可靠的方案,是避开裸字符数组操作——用 std::string、std::array<char n></char> 或 RAII 封装的 buffer 类。安全函数只是补丁,不是根基。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











