格式化多个百分号的字符串

时间:2017-06-27 09:54:56

标签: c printf string-formatting c-strings

我知道%%用于转义字符串中的实际%符号,因此%%%ds将以下列格式字符串中的%10s结尾,但我不知道我知道为什么我在这个字符串中需要%%5s

毕竟,只有两个额外的参数(BUFFSIZE / 10)。

#define BUFFSIZE 100
char buf[100]={0}
sprintf(buf, "%%5s %%%ds %%%ds", BUFFSIZE / 10, BUFFSIZE / 10);

运行上面的代码后,buf将包含字符串

%10s %10s 

3 个答案:

答案 0 :(得分:6)

目的是获取一个格式字符串,以便在另一个需要格式字符串sscanf()的函数中使用它。

使用您的代码:%5s %10s %10s写入bufsee online,这意味着它将接受三个带长度标识符的字符串。

%%5s          --> %5s
%%%ds with 10 --> %10s (read it that way: {%%}{%d}{s})

该缓冲区%5s %10s %10s现在可用于sscanf()调用,如here所示。

但最佳做法是防止由sscanf()导致的缓冲区溢出,Kernighan和Pike在其书The Practice of Programming中也对此进行了描述,请参阅here on SO

您可能无法使用%*s的原因可能是here on SO

  

对于printf,*允许您通过额外参数指定最小字段宽度,即printf("%*d", 4, 100);指定字段宽度为4.

     

对于scanf,*表示该字段将被读取但被忽略,因此输入“12 34”的scanf("%*d %d", &i)将忽略12并将34读入整数i。< / p>

答案 1 :(得分:2)

%本身就是一个有效的转换说明符。正如C11中提到的那样,规定的语法是第7.21.6.1 / P2章,(强调我的

  

每个转换规范都由字符%引入。 %之后,以下内容   按顺序出现:

     
      
  • 零个或多个标志[...]

  •   
  • 可选的最小字段宽度。

  •   
  • 可选的精度[...]

  •   
  • 可选的长度修饰符[...]

  •   
  • 转换说明符字符,用于指定要应用的转化类型。

  •   

然后,从P8开始,转换说明符

  

转换说明符及其含义为:

     

...

     

%

     

写入%个字符。没有参数被转换。完整的   转换规范应为%%

因此,基于贪心方法,编译器会将语法分组为

 ....   %%%ds, BUFFSIZE / 10 ....

as

 {%%}{%d}{s}
  ^^--------------------------Replaced as %
      ^^----------------------Actual conversion specification happens, argument is used
         ^^------------------just part of final output

最终产生

  %Xs    //where X is the value of (BUFFSIZE / 10)

这是一个有效的格式字符串( %,最小字段宽度,转换说明符,所有按顺序),再次,稍后将使用。

答案 2 :(得分:0)

OP正在计算参数大小的格式字符串。给定参数,该字符串将包含%5s %10s %10s,可与printfscanf一起使用:

printf("%5s %10s %10s", "A", "B", "C");

输出:

    A          B          C

char a[6], b[11], c[11];
scanf("%5s %10s %10s", a, b, c);

会将3个字符串读入abc,但会限制为每个字符串读取的字符数,以防止缓冲区溢出。

但请注意,对于printf情况,没有必要将字符串计算为已发布,因为您可以使用:

printf("%5s %*s %*s", "A", BUFFSIZE / 10, "B", BUFFSIZE / 10, "C");

不幸的是,scanf()将不同的语义附加到*格式修饰符,并且无法使用参数指定要存储的最大字符数,只能使用格式字符串中的数字,因此需要用于单独的格式化步骤。