snprintf在空终止符之后是否破坏缓冲区?

huangapple go评论65阅读模式
英文:

Does snprintf clobber the buffer after null-terminator?

问题

snprintf函数将'h''i''\0'写入buffer。根据标准,snprintf不会触及buffer[3]buffer[4]的内容。在Visual Studio 2019中,未使用的缓冲区通常会保持不变,但这是标准行为。

英文:

Consider the following code:

char buffer[5]{};
snprintf(buffer, sizeof(buffer), "hi");

snprintf writes 'h', 'i' and '\0' to buffer.

My question is: is there any guarantee that the snprintf won't touch buffer[3] and buffer[4] according to the standard? Visual Studio 2019 keeps the unused buffer untouched, but is this a standard behavior?

答案1

得分: 2

以下是翻译好的部分:

N1548 草案 ISO/IEC 9899:201x 编程语言 — C

7.21.6.5 snprintf 函数

概要

#include <stdio.h>
int snprintf(char * restrict s, size_t n,
const char * restrict format, ...);


**描述**

2. **`snprintf`** 函数与 **`fprintf`** 等效,不同之处在于输出写入一个数组(由参数 **`s`** 指定),而不是写入流。如果 **`n`** 为零,则不写入任何内容,**`s`** 可以是空指针。否则,超过第 **`n-1`** 个位置的输出字符将被丢弃,而不会写入数组,并在实际写入数组的字符末尾写入空字符。如果在重叠的对象之间进行复制,则行为是未定义的。

**返回值**

3. **`snprintf`** 函数返回将会被写入的字符数,如果 **`n`** 足够大,不包括终止的空字符,或者如果发生编码错误则返回负值。因此,只有在返回值为非负且小于 **`n`** 时,才完全写入以空字符结尾的输出。

它清楚地定义了将写入多少字符。它不保证在返回值 + 1 后目标缓冲区中的字符不被修改。

如果在 POSIX 环境中运行代码,并且如果这种保证是必需的,可以使用使用 `fmemopen()` 打开的内存流,并与 `fprintf()` 一起使用。`fprintf()` 保证不会在终止空字符之后修改字符。

```c
char buffer[5]{};
FILE* f = fmemopen(buffer, sizeof(buffer), "w");
fprintf(f, "hi");
fclose(f);
英文:

The N1548 draft ISO/IEC 9899:201x Programming languages — C

> 7.21.6.5 The snprintf function
>
> Synopsis
>
> 1. ```
> #include <stdio.h>
> int snprintf(char * restrict s, size_t n,
> const char * restrict format, ...);
> Description
>
> 2. The snprintf function is equivalent to fprintf, except that the output is written into an array (specified by argument s) rather than to a stream. If n is zero, nothing is written, and s may be a null pointer. Otherwise, output characters beyond the n-1<span/>st are discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array. If copying takes place between objects that overlap, the behavior is undefined.
>
> Returns
>
> 3. The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.

It clearly defines how much characters would be written. It does not guarantee that characters are not modified in the target buffer after the returned value + 1.

If you run your code in POSIX environment and if such the guarantee is a requirement, you can use a memory stream opened with fmemopen() and used with fprintf(). fprintf() guarantees that it will not modify characters after the terminating null character.

char buffer[5]{};
FILE* f = fmemopen(buffer, sizeof(buffer), &quot;w&quot;);
fprintf(f, &quot;hi&quot;);
fclose(f);

答案2

得分: 0

我无法想到一个原因,它会改变剩余空间中的内容。但如果你担心这一点,可以在代码中像下面这样调用snprintf()之前确定长度。

int main() {
    char buffer[5]{};
    char p[] = "hi";
    size_t len = strlen(p);
    size_t num = len < sizeof(buffer) ? len + 1 : sizeof(buffer);
    snprintf(buffer, num, p);
    return 0;
}
英文:

I cannot think of a reason that it will alter content in the remaining space. But if you are worried about that, determine the length before calling snprintf() in the code like below.

int main() {
	char buffer[5]{};
	char p[] = &quot;hi&quot;;
	size_t len = strlen(p);
	size_t num = len &lt; sizeof(buffer) ? len + 1 : sizeof(buffer);
	snprintf(buffer, num, p);
    return 0;
}

huangapple
  • 本文由 发表于 2023年5月29日 12:46:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76354738.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定