0

谁能解释一下这些输出背后的逻辑?我想这里*被用作抑制字符,但我无法弄清楚输出。

main()
{
char *s="hello world";
int i=7;
printf("%.*%s",s);
}

输出:%s

如果您替换 printf 语句,printf("%,*%s",s)那么您的输出将是 ,*hello world???

4

3 回答 3

6

printf 格式字符串"%.*%s"无效。该*字符不被视为转换抑制说明符,而是作为.指定精度的字符的参数。

与以下内容进行比较:

printf("%.*s", 3, str);

其中*将下一个参数 (3) 作为精度字段(对字符串具有特殊含义),然后s将字符串作为参数。由于3是一个常数,这相当于在格式字符串中对其进行硬编码:

printf("%.3s", str);

因此,您所拥有的是%.*看起来像是具有可变精度字段的转换的开始。它将使用s参数并将其视为int未定义的行为。

即使下一个参数实际上是一个 int,那么接下来会发生的事情是变量精度%后面的字符*不是有效的转换说明符。或者,更确切地说,它是一个有效的转换说明符,作为%%转换的一部分。但是%%编码文字的顺序%不支持两个字符之间的可选材料。ISO 9899:1999 说(在%说明符中)“完整的转换规范应为%%.”。

它还说“如果转换规范无效,则行为未定义”。中间有诸如宽度或精度字段之类的材料的%%规范是无效的,因为它违反了明确规定的“完整的转换规范应为%%”的要求。

于 2013-07-16T01:02:56.743 回答
1

在这里,您的格式化字符串已被解释为两部分"%.*%""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 页):

% 匹配单个 %:不发生转换或赋值。完整的转换规格应为 %%

因此,在两个百分号之间插入任何其他转换说明符会导致未定义的行为。

于 2013-07-16T01:02:21.843 回答
1

要回答您的具体问题,您的第一个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

*这种情况下是精度,因为它跟在小数点后面。对于字符串,这意味着要打印的字符串中的最大字符数。

于 2013-07-16T01:03:23.263 回答