在printf语句中使用*

时间:2013-07-16 00:53:02

标签: c

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

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

输出:%s

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

3 个答案:

答案 0 :(得分:6)

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

比较类似:

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

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

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

所以你在这里的是%.*,它看起来像是一个带有可变精度字段的转换的开始。它将使用s参数并将其视为int,这是未定义的行为。

即使下一个参数实际上是一个int,接下来发生的事情是,%变量精度之后的*字符不是有效的转换说明符。或者,它是有效的转化说明符,是%%转化的一部分。但编码文字%%的{​​{1}}序列不支持两个字符之间的可选材料。 ISO 9899:1999(%说明符)说“完整转换规范应为%。”

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

答案 1 :(得分:1)

此处,您的格式化字符串已被解释为两个部分"%.*%""s",其中前一个是带有指定最大宽度的“转义”百分号(这就是您的{{1} }指针*的值。请先尝试删除第二个百分号。

对不起,我想我会先为你试试,但这对我来说很不方便..

<强>编辑:

是的,为了得到你想要的东西你应该这样写:

s

重新编辑:

Plz check the reference manual of printf

  

宽度:
  此处使用十进制值指定字段的宽度。如果该值不足以填充宽度,则字段的其余部分将填充空格(除非指定了0标志)。如果该值溢出字段的宽度,则扩展该字段以适合该值。如果使用*代替宽度指定符,则下一个参数(必须是int类型)指定字段的宽度。注意:当使用带宽度和/或精度说明符的*时,首先是width参数,然后是precision参数,然后是要转换的值。

YET AGAIN EDITED:

@Kaz对标准是正确的。参见ISO-IEC-9899_1990(第2版第137页):

  

%匹配单个%:不进行转换或分配。完全转换   规范应为%%

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

答案 2 :(得分:1)

要回答您的具体问题,您的第一个printf()语句格式不正确,因为它没有为*修饰符提供int参数,并且对{{1}使用精度转换说明符未定义。在你的情况下,你的C实现似乎忽略了精度,所以你的print语句相当于:%,它应该导致输出:

printf("%%s",s);

%s 转换为输出中的%%

对于您的第二个%语句,它再次格式不正确,因为您提供了无效的转换说明符,即printf()。使用此说明符的行为会导致未定义的行为。您的系统似乎输出了错误的说明符,然后输出,,然后处理输出您的字符串的*

%s

,*hello world 中,转换说明符的printf()修饰符是一种从*调用的参数提供字段宽度或精度(或两者)的方式(而不是硬编码数字直接进入格式字符串本身)。所以:

printf()

将打印输出:

char *s="hello world";
int i=7;
printf("%.*s\n", i, s);

在这种情况下hello w 是精度,因为它跟随小数点。对于字符串,这表示将要打印的字符串中的最大字符数。