谁能解释一下这些输出背后的逻辑?我想这里*
被用作抑制字符,但我无法弄清楚输出。
main()
{
char *s="hello world";
int i=7;
printf("%.*%s",s);
}
输出:%s
如果您替换 printf 语句,printf("%,*%s",s)
那么您的输出将是 ,*hello world???
谁能解释一下这些输出背后的逻辑?我想这里*
被用作抑制字符,但我无法弄清楚输出。
main()
{
char *s="hello world";
int i=7;
printf("%.*%s",s);
}
输出:%s
如果您替换 printf 语句,printf("%,*%s",s)
那么您的输出将是 ,*hello world???
printf 格式字符串"%.*%s"
无效。该*
字符不被视为转换抑制说明符,而是作为.
指定精度的字符的参数。
与以下内容进行比较:
printf("%.*s", 3, str);
其中*
将下一个参数 (3) 作为精度字段(对字符串具有特殊含义),然后s
将字符串作为参数。由于3
是一个常数,这相当于在格式字符串中对其进行硬编码:
printf("%.3s", str);
因此,您所拥有的是%.*
看起来像是具有可变精度字段的转换的开始。它将使用s
参数并将其视为int
未定义的行为。
即使下一个参数实际上是一个 int,那么接下来会发生的事情是变量精度%
后面的字符*
不是有效的转换说明符。或者,更确切地说,它是一个有效的转换说明符,作为%%
转换的一部分。但是%%
编码文字的顺序%
不支持两个字符之间的可选材料。ISO 9899:1999 说(在%
说明符中)“完整的转换规范应为%%
.”。
它还说“如果转换规范无效,则行为未定义”。中间有诸如宽度或精度字段之类的材料的%%
规范是无效的,因为它违反了明确规定的“完整的转换规范应为%%
”的要求。
在这里,您的格式化字符串已被解释为两部分"%.*%"
,"s"
其中前一个是“转义”百分号,具有指定的最大宽度(这就是您在此处*
所做的)指针的值s
。尝试先删除第二个百分号。
抱歉,我想我会先为您尝试一下,但目前对我来说不方便..
编辑:
是的,要得到你想要的,你应该这样写:
// here width is a customized value you pass to specify the maximum width of string
printf("%.*s", width, s);
// and this would give "hello worl" as its output. notice the missing "d"
printf("%.*s", 10, s);
再次编辑:
请检查参考手册printf
宽度:
此处以十进制值指定字段的宽度。如果该值不足以填充宽度,则该字段的其余部分用空格填充(除非指定了 0 标志)。如果值溢出字段的宽度,则扩展字段以适合该值。如果使用 * 代替宽度说明符,则下一个参数(必须是 int 类型)指定字段的宽度。注意:当将 * 与宽度和/或精度说明符一起使用时,首先是宽度参数,然后是精度参数,然后是要转换的值。
再次编辑:
@Kaz 对标准的看法是正确的。请参阅 ISO-IEC-9899_1990(第 2 版第 137 页):
% 匹配单个 %:不发生转换或赋值。完整的转换规格应为 %%
因此,在两个百分号之间插入任何其他转换说明符会导致未定义的行为。
要回答您的具体问题,您的第一个printf()
语句格式不正确,因为它没有为修饰符提供 int 参数,并且未定义*
对转换说明符的精度使用。%
在您的情况下,您的 C 实现似乎忽略了精度,因此您的 print 语句等效于: printf("%%s",s);
,这应该导致输出:
%s
(在输出中%%
转换为 a %
)。
对于您的第二个printf()
语句,它又是格式错误的,因为您提供了一个无效的转换说明符,即,
. 使用此说明符的行为会导致未定义的行为。您的系统似乎输出了错误的说明符,然后输出*
,然后处理%s
输出您的字符串的。
,*hello world
在printf()
中,*
转换说明符的修饰符是一种从参数向printf()
调用提供字段宽度或精度(或两者)的方式(而不是直接将硬编码数字输入格式字符串本身)。所以:
char *s="hello world";
int i=7;
printf("%.*s\n", i, s);
将打印输出:
hello w
在*
这种情况下是精度,因为它跟在小数点后面。对于字符串,这意味着要打印的字符串中的最大字符数。