strcat vs strncat - 什么时候应该使用哪个函数?

时间:2011-06-27 09:41:14

标签: c string

为了安全起见,一些静态代码分析工具建议所有strcat用法都应该替换为strncat?

在一个程序中,如果我们清楚地知道目标缓冲区和源缓冲区的大小,是否仍然建议使用strncat?

另外,根据静态工具的建议,是否应该使用strcat?

5 个答案:

答案 0 :(得分:13)

将两个字符串连接成一个字符串。

<强> 原型

#include <string.h>

char * strcat(char *restrict s1, const char *restrict s2);

char * strncat(char *restrict s1, const char *restrict s2, size_t n);

<强> 说明

strcat()strncat()函数附加一个以null结尾的副本  字符串s2到以null结尾的字符串s1的末尾,然后添加一个终止\ 0'。字符串s1必须有足够的空间来容纳  结果

strncat()函数从s2追加不超过n个字符,和  然后添加一个终止\ 0'。

源行为和目标字符串不应重叠,因为行为是  未定义。

返回值

 The `strcat()` and `strncat()` functions return the pointer s1.

安全注意事项

strcat()函数很容易被滥用,使恶意用户可以随意更改正在运行的程序的功能  通过缓冲区溢出攻击。

避免使用strcat()。相反,请使用strncat()strlcat()并确保  没有更多的字符被复制到目标缓冲区  持。

请注意,strncat()也可能存在问题。根本要截断字符串可能是一个安全问题。由于截断的字符串  将不会与原始资源一样长,它可能指的是完全不同的资源,并且截断资源的使用可能导致非常  行为不正确。例如:

void
 foo(const char *arbitrary_string)
 {
         char onstack[8] = "";

 #if defined(BAD)
         /*
          * This first strcat is bad behavior.  Do not use strcat!
          */
         (void)strcat(onstack, arbitrary_string);        /* BAD! */
 #elif defined(BETTER)
         /*
          * The following two lines demonstrate better use of
          * strncat().
          */
         (void)strncat(onstack, arbitrary_string,
             sizeof(onstack) - strlen(onstack) - 1);
 #elif defined(BEST)
         /*
          * These lines are even more robust due to testing for
          * truncation.
          */
         if (strlen(arbitrary_string) + 1 >
             sizeof(onstack) - strlen(onstack))
                 err(1, "onstack would be truncated");
         (void)strncat(onstack, arbitrary_string,
             sizeof(onstack) - strlen(onstack) - 1);
 #endif
 }

<强> 实施例

char dest[20] = "Hello";
char *src = ", World!";
char numbers[] = "12345678";

printf("dest before strcat: \"%s\"\n", dest); // "Hello"

strcat(dest, src);
printf("dest after strcat:  \"%s\"\n", dest); // "Hello, World!"

strncat(dest, numbers, 3); // strcat first 3 chars of numbers
printf("dest after strncat: \"%s\"\n", dest); // "Hello, World!123"

答案 1 :(得分:10)

如果您完全确定源缓冲区的大小并且源缓冲区包含终止字符串的NULL字符,那么当目标缓冲区足够大时,您可以安全地使用strcat。

我仍然建议使用strncat并为其指定目标缓冲区的大小 - 目标字符串的长度 - 1

注意:我对此进行了编辑,因为评论指出我之前的回答非常错误。

答案 2 :(得分:1)

他们没有做同样的事情,所以他们不能互相替代。两者都有不同的数据模型。

  • strcat的字符串为空 已终止的字符串,您(作为程序员)保证它有足够的空间。
  • strncat的字符串是一个序列 char的任何一个被终止 在您指示的长度 如果是,则通过空终止 应该比那短 长度。

因此,这些功能的使用仅取决于您可能(或想要)对您的数据做出的假设。

答案 3 :(得分:0)

静态工具通常很难理解使用函数的情况。我打赌他们中的大多数只是警告每个遇到的strcat而不是实际查看传递给函数的数据是否是确定性的。如前所述,如果您可以控制输入数据,则功能都不安全。

虽然注意strncat()稍慢,因为它必须检查'\ 0'终止和计数器,并且还明确地将它添加到结尾。另一方面,strcat()只检查'\ 0',并通过从第二个字符串复制终结符以及所有数据,将尾部'\ 0'添加到新字符串。

答案 4 :(得分:-1)

非常简单的strcat用于连接两个字符串,例如

String a= data 
String b = structures 

如果使用,请执行strcat

Strcat(a, b) 

然后

a= data structures

但是,如果要连接单词r元素的特定数目,则可以使用strncat 例如,如果您只想将b的前两个字母lt连接到a中,则必须编写 Strncat(a,b,2) (这意味着您只需将拳头b的两个字母关联到​​a中,a就会变成 a =数据st