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
。如果dest
是char*
,那么你需要确保为它分配足够的内存,你不会得到任何编译错误。但是在你的程序中dest
有一个固定的大小,并且strcpy_s
与strcpy
不同,它检查目标缓冲区的大小(如果可以,在这种情况下它可以,因为它的大小是在编译时定义的)。
阅读本文
http://www.cplusplus.com/forum/beginner/118771/
基本上strcpy_s
是strcpy
的“安全”版本,它不允许你溢出。
从标准:
C (2011) 和 ISO/IEC WDTR 24731 - strcpy_s
:strcpy
的变体,在复制前检查目标缓冲区大小。在内部,可能strcpy_s
断言sizeof(dest)<SIZE
。
【讨论】:
如何查看目标缓冲区大小? withsizeof
,我刚刚编辑了我的评论 :) 但它只适用于静态定义的数组,不适用于指针,编译器不知道你有多少内存(如果有的话)分配给。
所以我们无法获得 dest 的大小?
不,它可以转换为指针,但是 sizeof(char[5])
是 5,而不是 sizeof(char*)
,它通常是 32 位(如果您有 64 位操作系统,则为 64 位)。只需做一个printf("%d ",sizeof(dest));
来说服自己:) 任何静态定义的数组上的sizeof
都会返回数组的大小。
谢谢..我知道这个,但是当我们调用一个函数时,使用 char[5] 作为参数,它会变成一个指针..所以不能得到它的大小,是对吗?以上是关于strcpy_s 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章