strcpy_s 是如何工作的?

Posted

技术标签:

【中文标题】strcpy_s 是如何工作的?【英文标题】:How does strcpy_s work? 【发布时间】:2014-06-12 00:04:35 【问题描述】:

众所周知,strcpy_s 是 strcpy 的安全版本。

但我想知道它是如何工作的......

让我们看一些例子。

strpy_s的声明:errno_t strcpy_s(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)

eg1

char dest[5];
char* src = "abcdefg";
strcpy_s(dest,5,src);

它将返回一个断言。 我想我可以理解这一点,使用 _SIZE 确保我们不能复制超过 _SIZE

的字符

但是..我无法理解:

char dest[5];
char* src = "abcdefg";
strcpy_s(dest,10,src);

我们仍然可以得到一个断言,这是怎么发生的?

ps,错误是:

Debug Assertion Failed 表达式:(L"Buffer is too small "&&0)

在VS2013中

strcpy_s 会检查它体内的 dest 的大小吗?如果是真的,怎么办?如何检查像_DEST这样的指针?

【问题讨论】:

仔细阅读文档:MSDN 你的第二个例子是错误的。 _SIZE 参数必须正确给出缓冲区的大小。如果你给 _SIZE 10 但你的缓冲区只有 5,那么结果是未定义的。 strcpy_s 无法捕获此错误。 其实有一个断言。 【参考方案1】:

在 DEBUG 模式下,MicroSoft API 用 0xfd 填充缓冲区,因此它们可以检查溢出。

此函数不会截断复制的字符串,但会引发异常!

指定目标缓冲区的大小(使用 _countof 而不是 sizeof)总是很痛苦,主要是在使用指针时!

这些“_s”API 比标准 API 有更多问题!!

【讨论】:

【参考方案2】:

这实际上是如何在运行时获取堆栈数组的大小而不将其衰减为指针:

template<typename T, size_t N> 
size_t arrSize(T (&array)[N])  

  return N;

您将其作为模板引用发送,模板机制会推导出大小。所以,你可以做类似的事情

int myArray[10];
cout << arrSize(myArray); // will display 10

所以我猜这就是“安全”MS strcpy_s 检查尺寸的方式。否则,如果您只传递一个指针,则没有标准兼容的方式来获取大小。

【讨论】:

好点!我对 C++ 不是很熟悉,我想我需要一些时间在 C++ 中的模板上 :) 谢谢! 为什么这是一个公认的答案?问题是关于 C 的。【参考方案3】:

MSDN 说“strcpy_s 函数将 strSource 地址中的内容(包括终止空字符)复制到 strDestination 指定的位置。目标字符串必须足够大以容纳源字符串及其终止空字符。如果源字符串和目标字符串重叠,则 strcpy_s 的行为未定义。"

【讨论】:

所以不是那么“安全”? 你对安全的定义是什么? 当我们尝试使用这个函数时,比如 strcpy_s(dest,10,src);我们会得到异常或什么都不做 考虑到微软创建了这个功能,微软不应该定义“安全”的含义并在文档中解释它吗?如果他们想让我们使用它,那么他们不应该解释为什么它“更安全”吗? 这是安全的,因为可以通过避免缓冲区溢出和空指针问题来防止未定义的行为。在内存重叠的情况下,仍可能发生未定义的行为。我不确定微软是否很好地定义了安全。似乎更多的是为错误条件提供定义的行为。如果 strcpy_s 与太小的目标缓冲区一起使用,则默认行为仍然是中止程序,但避免了缓冲区溢出。【参考方案4】:

dest 不能容纳超过 5 个字符,这就是您收到错误的原因。不是因为_SIZE。如果destchar*,那么你需要确保为它分配足够的内存,你不会得到任何编译错误。但是在你的程序中dest 有一个固定的大小,并且strcpy_sstrcpy 不同,它检查目标缓冲区的大小(如果可以,在这种情况下它可以,因为它的大小是在编译时定义的)。 阅读本文

http://www.cplusplus.com/forum/beginner/118771/

基本上strcpy_sstrcpy 的“安全”版本,它不允许你溢出。 从标准: C (2011) 和 ISO/IEC WDTR 24731 - strcpy_sstrcpy 的变体,在复制前检查目标缓冲区大小。在内部,可能strcpy_s 断言sizeof(dest)&lt;SIZE

【讨论】:

如何查看目标缓冲区大小? with sizeof,我刚刚编辑了我的评论 :) 但它只适用于静态定义的数组,不适用于指针,编译器不知道你有多少内存(如果有的话)分配给。 所以我们无法获得 dest 的大小? 不,它可以转换为指针,但是 sizeof(char[5]) 是 5,而不是 sizeof(char*),它通常是 32 位(如果您有 64 位操作系统,则为 64 位)。只需做一个printf("%d ",sizeof(dest)); 来说服自己:) 任何静态定义的数组上的sizeof 都会返回数组的大小。 谢谢..我知道这个,但是当我们调用一个函数时,使用 char[5] 作为参数,它会变成一个指针..所以不能得到它的大小,是对吗?

以上是关于strcpy_s 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

如何将当前的 strcpy 转换为 strcpy_s?

strcpy_s 不适用于 gcc

将 strcpy_s 用于 TCHAR 指针(Microsoft 特定)

C语言 strcpy_s 函数

关于strcpy_s

例外:使用 strcpy_s 时访问冲突写入位置