在同一调用中打印 %n 的值 - 毫无意义?

printf the value of %n in the same call - senseless?

本文关键字:的值 毫无意义 打印 调用      更新时间:2023-10-16

我在 cppreference.com 找不到printf规范的以下部分的意图:

每次转换的操作后都有一个序列点 规范;这允许在同一%n中存储多个%n结果 变量并打印 %n 之前存储的值 叫。

这读起来好像一个(甚至几个)%n转换说明符的结果可以打印在同一个printf语句中。 但是我无法找到如何实现这一点,因为所有传递给printf调用的参数都是在输入printf的主体之前被评估的(参数评估后有一个序列点)。因此,在printf有机会用"到目前为止写入的字符数"覆盖该变量的值之前,%n将写入的变量的值进行评估:

#include <stdio.h>
int main( int argc, char* argv[] )
{
int n = 0;
printf("Hello, world!%n (%d first n); %n (%d second n)", &n ,n, &n, n);
// will print out "Hello, world! (0 first n);  (0 second n)"
return 0;
}

我的问题:如果没有任何机会"在同一调用中打印 %n 之前存储的值",那么printf规范的相应部分是不是毫无意义或具有误导性?

c99标准声明的实际含义是什么:

7.19.6 格式化输入/输出函数 (1) 格式化的输入/输出函数的行为应像在 与每个说明符关联的操作。

是为了减少获得未定义行为的"机会"吗?

这个问题被标记为 c++ 和 c,因为我认为这个主题对这两种语言的适用方式相同。

这可能很疯狂,但我认为以下内容是合法的:

char s[2];
s[1] = '';
printf("Hi, world!%hhn%s", s, s);

%hhn获取指向字符的指针。它将10(到目前为止写入的字符数)写入s[0]。然后它打印字符串s,相当于"n"(char[]){ 10, 0 }(假设 ASCII)。

由于您正确识别的原因,您的代码确实只打印零。

标准中的声明仍然是必要的,因为其他地方的笼统措辞是,如果一个对象被写入不止一次而没有干预序列点,则程序的行为是未定义的。实际上,该语句是必要的,以说明您的代码没有未定义的行为(不像,例如,i = i++;)。

可以想象编译器将对printf的调用转换为一系列单独的fputs()调用,其中包含通过调用转换处理程序计算的字符串片段。 此实现可能会在打印n的值之前将值存储到n中。 这会不符合规定吗?

现代编译器已经对printf()进行了小的优化,例如将printf("Hello worldn");转换为puts("Hello world");,将printf("n");转换为fputchar('n');。 他们还检查格式字符串和参数一致性...进一步的优化将导致上述结果。