为什么应该使用 strncpy 而不是 strcpy?

发布于 2024-08-01 16:15:27 字数 1224 浏览 9 评论 0原文

编辑:我已经添加了示例的源代码。

我遇到了这个示例

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );

产生了这个输出:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

这让我想知道为什么有人会想要这种效果。 看起来会很混乱。 这个程序让我觉得你基本上可以用 Tom Bro763 复制某人的名字(例如 Tom Brokaw)。

使用 strncpy() 相对于 strcpy()有什么优点?

Edit: I've added the source for the example.

I came across this example:

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );

Which produced this output:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

Which makes me wonder why anyone would want this effect. It looks like it would be confusing. This program makes me think you could basically copy over someone's name (eg. Tom Brokaw) with Tom Bro763.

What are the advantages of using strncpy() over strcpy()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

卷耳 2024-08-08 16:15:27

strncpy() 函数在设计时考虑了一个非常特殊的问题:操作以原始 UNIX 目录条目的方式存储的字符串。 它们使用一个短的固定大小的数组(14 字节),并且仅当文件名比数组短时才使用 null 终止符。

这就是 strncpy() 的两个奇怪之处:

  • 如果目标完全填满,它不会在目标上放置一个空终止符; 它
  • 总是完全填充目的地,如果需要的话,用 null 填充。

对于“更安全的 strcpy()”,您最好使用 strncat() ,如下所示:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

这将始终终止结果,并且不会复制超过必要的。

The strncpy() function was designed with a very particular problem in mind: manipulating strings stored in the manner of original UNIX directory entries. These used a short fixed-sized array (14 bytes), and a nul-terminator was only used if the filename was shorter than the array.

That's what's behind the two oddities of strncpy():

  • It doesn't put a nul-terminator on the destination if it is completely filled; and
  • It always completely fills the destination, with nuls if necessary.

For a "safer strcpy()", you are better off using strncat() like so:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

That will always nul-terminate the result, and won't copy more than necessary.

伴我老 2024-08-08 16:15:27

虽然我知道 strncpy 背后的意图,但它并不是一个真正好的函数。 两者都避免。 雷蒙德·陈 (Raymond Chen) 解释

就我个人而言,我的结论是,如果您正在处理以 null 结尾的字符串,请避免使用 strncpy 及其所有朋友。 尽管名称中包含“str”,但这些函数不会生成以 null 结尾的字符串。 它们将空终止字符串转换为原始字符缓冲区。 在需要空终止字符串作为第二个缓冲区的地方使用它们是完全错误的。 如果源代码太长,您不仅无法获得正确的空终止,而且如果源代码很短,您还会得到不必要的空填充。

另请参阅为什么 strncpy 不安全?

While I know the intent behind strncpy, it is not really a good function. Avoid both. Raymond Chen explains.

Personally, my conclusion is simply to avoid strncpy and all its friends if you are dealing with null-terminated strings. Despite the "str" in the name, these functions do not produce null-terminated strings. They convert a null-terminated string into a raw character buffer. Using them where a null-terminated string is expected as the second buffer is plain wrong. Not only do you fail to get proper null termination if the source is too long, but if the source is short you get unnecessary null padding.

See also Why is strncpy insecure?

骄兵必败 2024-08-08 16:15:27

strncpy 通过要求您在其中输入长度来防止缓冲区溢出。 strcpy 取决于尾随 \0,这可能并不总是发生。

其次,为什么你选择只复制 7 个字符串上的 5 个字符超出了我的范围,但它产生了预期的行为。 它仅复制前 n 个字符,其中 n 是第三个参数。

n 函数全部用作针对缓冲区溢出的防御性编码。 请使用它们代替旧函数,例如 strcpy

strncpy combats buffer overflow by requiring you to put a length in it. strcpy depends on a trailing \0, which may not always occur.

Secondly, why you chose to only copy 5 characters on 7 character string is beyond me, but it's producing expected behavior. It's only copying over the first n characters, where n is the third argument.

The n functions are all used as defensive coding against buffer overflows. Please use them in lieu of older functions, such as strcpy.

森罗 2024-08-08 16:15:27

strncpy 并不比 strcpy 更安全,它只是将一种类型的错误与另一种类型的错误进行交换。 在 C 中,处理 C 字符串时,您需要知道缓冲区的大小,这是没有办法解决的。 strncpy 对于其他人提到的目录是合理的,但除此之外,你永远不应该使用它:

  • 如果你知道字符串和缓冲区的长度,为什么要使用 strncpy ? 这充其量只是浪费计算能力(添加无用的 0),那么您将面临默默截断字符串的风险,这并不比缓冲区溢出好多少
  • 如果您不知道长度,

strncpy is NOT safer than strcpy, it just trades one type of bugs with another. In C, when handling C strings, you need to know the size of your buffers, there is no way around it. strncpy was justified for the directory thing mentioned by others, but otherwise, you should never use it:

  • if you know the length of your string and buffer, why using strncpy ? It is a waste of computing power at best (adding useless 0)
  • if you don't know the lengths, then you risk silently truncating your strings, which is not much better than a buffer overflow
℉絮湮 2024-08-08 16:15:27

strncpy() 函数是更安全的函数:您必须传递目标缓冲区可以接受的最大长度。 否则,可能会发生源字符串未正确以 0 结尾的情况,在这种情况下,strcpy() 函数可能会将更多字符写入目标,从而破坏目标缓冲区之后内存中的任何内容。 这是许多漏洞利用中使用的缓冲区溢出问题

。此外,对于像 read() 这样的 POSIX API 函数,它不会将终止 0 放入缓冲区,而是返回读取的字节数,您可以手动输入 0,或使用 strncpy() 复制它。

在您的示例代码中,index实际上不是索引,而是一个count - 它告诉最多从源复制到目标的字符数。 如果source的前n个字节中没有空字节,则放置在destination中的字符串不会以空结尾

The strncpy() function is the safer one: you have to pass the maximum length the destination buffer can accept. Otherwise it could happen that the source string is not correctly 0 terminated, in which case the strcpy() function could write more characters to destination, corrupting anything which is in the memory after the destination buffer. This is the buffer-overrun problem used in many exploits

Also for POSIX API functions like read() which does not put the terminating 0 in the buffer, but returns the number of bytes read, you will either manually put the 0, or copy it using strncpy().

In your example code, index is actually not an index, but a count - it tells how many characters at most to copy from source to destination. If there is no null byte among the first n bytes of source, the string placed in destination will not be null terminated

萧瑟寒风 2024-08-08 16:15:27

您正在寻找的是函数 strlcpy() ,它总是以 0 终止字符串并初始化缓冲区。 它还能够检测溢出。 唯一的问题是,它不是(真正)可移植的,并且仅存在于某些系统(BSD、Solaris)上。 这个函数的问题在于它打开了另一个蠕虫罐头,正如关于
http://en.wikipedia.org/wiki/Strlcpy

我个人的观点是,它很大程度上比 strncpy()strcpy() 更有用。 它具有更好的性能,是 snprintf() 的良好伴侣。 对于没有它的平台来说,实现起来相对容易。
(对于应用程序的开发阶段,我将这两个函数(snprintf()strlcpy())替换为陷阱版本,该版本会在缓冲区溢出或截断时残酷中止程序.这可以快速捕获最严重的违规者,特别是如果您使用其他人的代码库,则

可以轻松实现:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}

What you're looking for is the function strlcpy() which does terminate always the string with 0 and initializes the buffer. It also is able to detect overflows. Only problem, it's not (really) portable and is present only on some systems (BSD, Solaris). The problem with this function is that it opens another can of worms as can be seen by the discussions on
http://en.wikipedia.org/wiki/Strlcpy

My personal opinion is that it is vastly more useful than strncpy() and strcpy(). It has better performance and is a good companion to snprintf(). For platforms which do not have it, it is relatively easy to implement.
(for the developement phase of a application I substitute these two function (snprintf() and strlcpy()) with a trapping version which aborts brutally the program on buffer overflows or truncations. This allows to catch quickly the worst offenders. Especially if you work on a codebase from someone else.

EDIT: strlcpy() can be implemented easily:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}
等你爱我 2024-08-08 16:15:27

对我来说,将字符串复制到另一个字符串并在达到目的地限制时停止的最干净的方法是 snprintf

#include <stdio.h>

int main()
{
    char src[] = "Some example...";
    char dest1[50], dest2[5];

    snprintf(dest1, sizeof(dest1), "%s", src);
    snprintf(dest2, sizeof(dest2), "%s", src);

    printf("%s\n", dest1);
    printf("%s\n", dest2);

    return 0;
}

输出:

Some example...
Some

但可能不是最有效的。

更新

实际上我们可以直接使用sprintf特殊修饰符 %.*s,这需要一个附加参数(放在要复制的参数字符串之前),它指定要复制的最大字符数。

#include <stdio.h>

int main()
{
    char src[] = "Some example...";
    char dest1[50], dest2[5];

    sprintf(dest1, "%.*s", (int) sizeof(dest1) - 1, src);
    sprintf(dest2, "%.*s", (int) sizeof(dest2) - 1, src);

    printf("%s\n", dest1);
    printf("%s\n", dest2);

    return 0;
}

输出:

Some example...
Some

For me the most clean way to copy a string into another and stop if you reach the destination's limit is snprintf

#include <stdio.h>

int main()
{
    char src[] = "Some example...";
    char dest1[50], dest2[5];

    snprintf(dest1, sizeof(dest1), "%s", src);
    snprintf(dest2, sizeof(dest2), "%s", src);

    printf("%s\n", dest1);
    printf("%s\n", dest2);

    return 0;
}

Outputs:

Some example...
Some

But maybe not the most efficient.

Update

Actually we may directly use sprintf with the special modifier %.*s, this expects an additional argument (put before the argument string to copy) which specifies the maximum number of characters to copy.

#include <stdio.h>

int main()
{
    char src[] = "Some example...";
    char dest1[50], dest2[5];

    sprintf(dest1, "%.*s", (int) sizeof(dest1) - 1, src);
    sprintf(dest2, "%.*s", (int) sizeof(dest2) - 1, src);

    printf("%s\n", dest1);
    printf("%s\n", dest2);

    return 0;
}

Outputs:

Some example...
Some
一指流沙 2024-08-08 16:15:27

strncpy 使用 '\0' 来填充目标的源大小,即使目标的大小较小......

联机帮助页:

如果 src 的长度小于 n,strncpy() 会填充剩余部分
dest 带有空字节。

不仅是余数...还有在此之后直到 n 个字符
到达。 因此你会得到溢出......(参见手册页
实施)

strncpy fills the destination up with '\0' for the size of source, eventhough the size of the destination is smaller....

manpage:

If the length of src is less than n, strncpy() pads the remainder of
dest with null bytes.

and not only the remainder...also after this until n characters is
reached. And thus you get an overflow... (see the man page
implementation)

若水般的淡然安静女子 2024-08-08 16:15:27

这可以用在许多其他场景中,在这些场景中,您只需将原始字符串的一部分复制到目标。 使用 strncpy() 可以复制原始字符串的有限部分,这与 strcpy() 不同。 我看到您提供的代码来自 publib.boulder.ibm.com

This may be used in many other scenarios, where you need to copy only a portion of your original string to the destination. Using strncpy() you can copy a limited portion of the original string as opposed by strcpy(). I see the code you have put up comes from publib.boulder.ibm.com.

太阳男子 2024-08-08 16:15:27

这取决于我们的要求。
对于 Windows 用户

每当我们不想复制整个字符串或只想复制 n 个字符时,我们就使用 strncpy。 但 strcpy 复制整个字符串,包括终止空字符。

这些链接将帮助您更多地了解 strcpy 和 strncpy
以及我们可以在哪里使用。

关于 strcpy

关于 strncpy

That depends on our requirement.
For windows users

We use strncpy whenever we don't want to copy entire string or we want to copy only n number of characters. But strcpy copies the entire string including terminating null character.

These links will help you more to know about strcpy and strncpy
and where we can use.

about strcpy

about strncpy

彻夜缠绵 2024-08-08 16:15:27

strncpy 是 strcpy 的更安全版本,事实上您永远不应该使用 strcpy,因为它潜在的缓冲区溢出漏洞使您的系统容易受到各种攻击

the strncpy is a safer version of strcpy as a matter of fact you should never use strcpy because its potential buffer overflow vulnerability which makes you system vulnerable to all sort of attacks

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文