可能printf(或fprintf或dprintf)返回(“成功”)少于(所有字节)的数量(但非负)?

时间:2016-11-17 16:42:48

标签: c printf return-value

手册说

  

成功返回后,这些函数[printf,dprintf等]将返回打印的字符数。

手册提及这个数字可能比“最终”(替换和格式化完成)字符串的长度少(但是非负)。也没有提到如何检查(或实现)字符串是否完全写。

dprintf函数对文件描述符进行操作。类似于函数,手册 提及

  

成功时,返回写入的字节数(零表示没有写入)。如果此数字小于请求的字节数,则不是错误;

因此,如果我想完全写一个字符串,那么我必须将n = write()括在一个while循环中。在 dprintf printf 的情况下,我是否必须这样做?

4 个答案:

答案 0 :(得分:2)

我对documentation的理解是dprintf会失败或输出所有输出。但我同意这是一些灰色地带(我可能不太了解);我猜测部分输出是某种失败(因此返回负值)。

以下是musl-libc的实施:

stdio/dprintf.c dprintf功能只调用vdprintf

但在stdio/vdprintf.c你只有:

static size_t wrap_write(FILE *f, const unsigned char *buf, size_t len)
{
    return __stdio_write(f, buf, len);
}

int vdprintf(int fd, const char *restrict fmt, va_list ap)
{
    FILE f = {
        .fd = fd, .lbf = EOF, .write = wrap_write,
        .buf = (void *)fmt, .buf_size = 0,
        .lock = -1
    };
    return vfprintf(&f, fmt, ap);
}

所以dprintf返回的格式类似于vfprintf(和fprintf ....)。

但是,如果您真的担心,最好使用snprintfasprintf输出到某个内存缓冲区,并在该缓冲区上明确使用write(2)

查看stdio/__stdio_write.c __stdio_write的实现(它在循环中使用带有两个数据块的向量的writev(2))。

换句话说,我常常不在乎;但是如果你真的需要确保每个字节都按照你的预期写入(例如,如果文件描述符是某个HTTP套接字),我建议缓冲显式(例如通过调用{{ 1}}和/或snprintf)您自己,然后使用您明确的write(2)

PS。您可以自己检查提供asprintf您的特定C标准库的源代码;对于GNU glibc,请参见libio/iovdprintf.c

答案 1 :(得分:1)

使用stdio,返回部分写入的字节数并没有多大意义,因为stdio函数可以使用(或多或少)全局缓冲区,其状态是未知的,并且从之前的调用中被拖入。

如果stdio函数允许你使用它,那么错误返回值将需要更复杂,因为它们不仅需要传达已输出或未输出的字符数,而且还需要在上次输入之前确认失败在缓冲区的某个地方,或者在上次输入的中间,如果是这样,最后输入的缓冲量是多少。

理论上,d函数可以很容易地为你提供部分写入字符的数量,但POSIX指定它们应该镜像stdio函数,因此它们只会在错误时给你一个未指定的负值。

如果您需要更多控制,可以使用较低级别的功能。

答案 2 :(得分:1)

关于printf(),很明显。

  

printf函数返回传输的字符数,如果发生输出或编码错误则返回负值。 C11dr§7.21.6.33

如果发生错误,则返回负值。在这种情况下,可能已打印了0个或更多字符。通过标准库无法知晓计数。

如果值返回不为负数,则为发送到stdout的数字。

由于stdout经常被缓冲,因此可能不是printf()结束时输出设备上收到的数字。使用printf()

关注fflush(stdout)
int r1 = printf(....);
int r2 = fflush(stdout);
if (r1 < 0 || r2 != 0) Handle_Failure();

要进行最精细的控制,请“打印”到缓冲区并使用putchar()或各种非标准功能。

答案 3 :(得分:0)

我打赌。 (在查看 printf 的 - 混淆 - 来源之后。)所以任何非负返回值意味着printf 完全成功(到达结束时)格式字符串,一切都传递给内核缓冲区) 但是一些(真实的)人应该确认它。