【发布时间】:2021-06-29 23:22:59
【问题描述】:
关于 strncpy 警告的另一个问题。
代码如下:
#include <cstring>
extern char g_dest[16];
extern char g_src[16];
char* mycopy()
{
char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
return x;
}
用g++ 8.3版编译:
$ g++ --version
g++ (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
strncpy-warning2.cxx: In function ‘char* mycopy()’:
strncpy-warning2.cxx:8:24: error: ‘char* strncpy(char*, const char*, size_t)’ output may be truncated copying 15 bytes from a string of length 15 [-Werror=stringop-truncation]
char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
警告可以通过以下任一方式解决:
- 使 g_src 比 g_dest 短:
$ cat strncpy-warning2.cxx
#include <cstring>
extern char g_dest[16];
extern char g_src[15];
char* mycopy()
{
char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
return x;
}
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
$
- 或者在
g_dest的末尾显式添加一个NUL终止符:
$ cat strncpy-warning2.cxx
#include <cstring>
extern char g_dest[16];
extern char g_src[16];
char* mycopy()
{
char * x = strncpy ( g_dest, g_src, sizeof ( g_dest ) - 1 );
g_dest[ sizeof( g_dest ) - 1 ] = '\0';
return x;
}
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
$
- 或者如果我将 g_src 设为指针而不是数组:
$ cat strncpy-warning2.cxx
#include <cstring>
extern char g_dest[16];
extern char* g_src2;
char* mycopy()
{
char * x = strncpy ( g_dest, g_src2, sizeof ( g_dest ) - 1 );
return x;
}
$ g++ -Wall -Wextra -Werror -O3 -c strncpy-warning2.cxx
$
我知道 GCC 正试图警告 strncpy 使用的潜在错误,但是,我不明白为什么我们不能在 2 个相同大小的数组上执行 strncpy?为什么警告信息是the output maybe truncated ? (即我找不到 output 可能是 truncated 的示例,除非 GCC 假定 g_src 不一定是有效的以 NUL 结尾的 c 字符串。)
通过谷歌搜索,我在 GCC bugzilla 中看到了类似的案例:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87028,但是,我不确定这是否相同,因为最后标记为 FIXED,但显然我的问题仍然存在GCC 10.2。
谢谢!
【问题讨论】:
-
strncpy(),尽管它的名字,不是设计用于字符串...char dst[4], src[4] = "foo"; strncpy(dst, src, 3);将离开dst[3]与它开始的任何随机垃圾,即dst不是字符串。 -
谢谢pmg。通过再次阅读 strncpy 的手册页,我明白了你的意思:“警告:如果 src 的前 n 个字节中没有空字节,则放在 dest 中的字符串不会以空值结尾。”。这就是为什么如果我在末尾明确添加 NUL,警告就消失了?
-
@LiuWei — 是的。
strncpy()之后的赋值确保结果是一个字符串。 -
感谢@Jonathan Leffler,看起来每当 strncpy 使用触发警告时,我至少应该在大多数用例中使用 memcpy。 (这对可读性和可维护性也更好,恕我直言)
-
初学者认为
strncpy是strcpy的“安全”版本,但事实并非如此,除非“安全”意味着完全不直观的东西。使用起来很棘手,应该避免使用。
标签: c++ c g++ gcc-warning