谁能解释一下这些输出背后的逻辑?我想这里*被用作抑制字符,但我无法弄清楚输出。
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
在*这种情况下是精度,因为它跟在小数点后面。对于字符串,这意味着要打印的字符串中的最大字符数。