【问题标题】:Format string with multiple percent signs使用多个百分号格式化字符串
【发布时间】:2017-11-30 07:57:08
【问题描述】:

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

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

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

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

%10s %10s 

【问题讨论】:

  • 我在buf 中得到%5s %10s %10s,这里是ideone.com/c8MhN6 的演示。 期待什么?
  • 这意味着某人要么过于聪明,要么不知道%*s
  • @n.m.或者,不怕维护者(Ref: 暴力精神病患者

标签: c printf string-formatting c-strings


【解决方案1】:

目的是获取一个格式字符串,以便在另一个需要格式字符串的函数中使用它,例如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。

【讨论】:

    【解决方案2】:

    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()* 格式修饰符附加了不同的语义,并且无法使用参数指定要存储的最大字符数,只能使用格式字符串中的数字,因此需要单独的格式一步。

    【讨论】:

      【解决方案3】:

      % 本身就是一个有效的转换说明符。如C11,第 7.21.6.1/P2 章中所述,规定的语法是(emphasis mine

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

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

      • 可选的最小字段宽度。

      • 可选精度 [...]

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

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

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

      转换说明符及其含义为:

      ......

      %

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

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

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

      作为

       {%%}{%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)
      

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

      【讨论】:

      • 你解释了一切,我的错
      • @VishwajeetVishu 没关系,没关系。与此同时,我也在更新答案。 :)
      猜你喜欢
      • 2015-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-02
      相关资源
      最近更新 更多