如果 strcat 函数中的目标字符串不是空终止的,它是否是未定义的行为?

Is it undefined behavior if the destination string in strcat function is not null terminated?

下面的程序

// Code has taken from http://ideone.com/AXClWb
#include <stdio.h>
#include <string.h>

#define SIZE1 5
#define SIZE2 10
#define SIZE3 15

int main(void){
    char a[SIZE1] = "Hello";
    char b[SIZE2] = " World";
    char res[SIZE3] = {0};

    for (int i=0 ; i<SIZE1 ; i++){
        res[i] = a[i];
    }

    strcat(res, b);
    printf("The new string is:  %s\n",res);
    return 0;
}

具有明确定义的行为。根据要求,源字符串 b 以 null 结尾。但是如果行

会是什么行为
char res[SIZE3] = {0};  // Destination string

替换为

char res[SIZE3];  

标准是否明确说明目标字符串也以空结尾?

如果您让 res 保持未初始化状态,那么在将 a 复制到 res 之后(在 for 循环中),res 中没有 NUL 终止符。因此,如果目标字符串不包含 NUL 字节,strcat() 的行为是未定义的。

基本上 strcat() 要求它的两个参数都是 strings(即两者都必须包含终止 NUL 字节)。否则,它是 undefined behaviour。这个 从 strcat():

的描述中可以明显看出

§7.23.3.2, strcat() function

The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1.

(强调我的)。

我认为man明确

Description

The strcat() function appends the src string to the dest string, overwriting the terminating null byte ('[=22=]') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable; buffer overruns are a favorite avenue for attacking secure programs.

强化我的

顺便说一句,我认为 strcat 在连接新字符串之前开始将 null terminator 搜索到目标字符串中,所以它显然是 UB,就 dest 字符串具有自动存储。

在建议的代码中

for (int i=0 ; i<SIZE1 ; i++){
    res[i] = a[i];
}

a5 个字符而不是空终止符复制到 res 字符串,因此从 514 的其他字节未初始化。

标准还说明了更安全的实现 strcat-s

K.3.7.2.1 The strcat_s function

Synopsis

    #define _ _STDC_WANT_LIB_EXT1_ _ 1
      #include <string.h>
      errno_t strcat_s(char * restrict s1,
           rsize_t s1max,
           const char * restrict s2);

Runtime-constraints

2 Let m denote the value s1max - strnlen_s(s1, s1max) upon entry to strcat_s.

我们可以看到 strlen_s 始终 return 它们是 dest 缓冲区的有效大小。从我的角度来看,引入此实现是为了避免问题的 UB。

如果 char res[SIZE3]; 堆栈上 ,它会有 random/undefined 东西在里面。
您永远不会知道 res[SIZE3] 中是否会有零字节,因此 strcat 未定义。

如果 char res[SIZE3]; 是一个 未初始化的全局 ,它将 全零 ,这将使其表现为空 c 字符串strcat 写入它是安全的(只要 SIZE3 足够大以容纳您追加的内容)。

TL;DR 是。


由于这是一个语言律师问题,让我加两分钱。

引用 C11,章节 §7.24.3.1/2(重点是我的

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

The strcat function appends a copy of the string pointed to by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1.[...]

并且,根据定义,string is null-terminated,引用 §7.1 .1/1

A string is a contiguous sequence of characters terminated by and including the first null character.

因此,如果源 char 数组不是以 null 结尾的(即,不是 字符串 ),strcat() 很可能超出搜索调用 undefined behavior.

结尾 的界限

根据您的问题,char res[SIZE3]; 是一个自动局部变量,将包含不确定的值,如果用作 strcat() 的目标,将调用 UB。