我正在尝试编写一个名为error的函数,其行为类似于printf,但仅支持%s,%c和%d说明符。但是,如果%后面没有合法字符,我无法理解printf的行为。我也尝试循环使用c99标准手册但找不到任何东西。有人可以帮助我吗?
答案 0 :(得分:8)
C99在§7.19.6.1/ 9(fprintf
)中有这个:
如果转换规范无效,则行为未定义。
因此,格式错误的格式字符串会导致未定义的行为。
如果格式字符串格式正确但参数实际上与类型不匹配,则相同:
如果任何参数不是相应转换规范的正确类型,则行为未定义。
答案 1 :(得分:0)
由于您似乎对实际发生的事情感兴趣,而不是您应该作为最佳做法所做的事情,我会解决这个问题并将其他人留给引用章和节。 : - )
格式字符串是printf
的“提示”,告诉它要处理多少字节,以及如何格式化它们。如果你给它错误的格式,它会很乐意处理你告诉它的参数,无论它们的实际类型如何。
根据这些字节的值,它们可能有意义,或者它们可能是胡言乱语。
这是一个简单的(依赖于实现的)示例:
#include <stdio.h>
void main(int argc, char *argv[]) {
int x = 10; // LF
x <<= 8;
x += 13; // CR
x <<= 8;
x += 73; // I
x <<= 8;
x += 72; // H
printf("x = %d (%08x)\n", x, x);
printf("%.4s", &x);
}
这将x
定义为(我的系统上的4字节)整数,其字节包含10
13
73
72`。这些字节恰好是换行符,回车符,I和H的ASCII码。
第一个printf
显示x
的小数和十六进制值,如果您自己计算它们,您会发现它们完全符合您的预期。
但第二个printf
将x
视为4个字符的字符串。由于我的机器是little-endian,它会反转字节顺序,因此它会打印对应于ASCII 72,73,13,10的字符,这些字符是
H
I
CR
LF
当然,正如Mat所说,这对于理解printf
背后的机制很有用,但是你不应该编写依赖于这种行为的代码。至少,它不是可移植的(例如,大端机器不会改变字节顺序)。
答案 2 :(得分:0)
这取决于printf
的编码方式。当在字符串中检测到%
时,函数将找到它希望看到的一个字符。如果它匹配则它将处理匹配的块。例如,如果您将float
传递给%d
,那么它将处理传递整数的变量,以防参数纯粹通过堆栈传递。同样,如果将int
传递给%f
,它会将整数位解释为系统的特定浮点表示。
同样在注释中指出R ..在参数通过寄存器传递的情况下,输出将是不同的。存储传递值的寄存器类型(FPU寄存器或通用寄存器或其他)。某个格式说明符将首先获取它遇到的寄存器中的第一个参数。
如果角色不匹配,请说k
,那么它可以只打印%k
作为字符串,或者执行函数实现的任何内容。
修改强>
看看Mat关于此事的C99标准规范的答案。