我知道%%
用于转义字符串中的实际%
符号,因此%%%ds
将以下列格式字符串中的%10s
结尾,但我不知道我知道为什么我在这个字符串中需要%%5s
?
毕竟,只有两个额外的参数(BUFFSIZE / 10)。
#define BUFFSIZE 100
char buf[100]={0}
sprintf(buf, "%%5s %%%ds %%%ds", BUFFSIZE / 10, BUFFSIZE / 10);
运行上面的代码后,buf将包含字符串
%10s %10s
答案 0 :(得分:6)
目的是获取一个格式字符串,以便在另一个需要格式字符串sscanf()
的函数中使用它。
使用您的代码:%5s %10s %10s
写入buf
,see 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
,可与printf
或scanf
一起使用:
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个字符串读入a
,b
,c
,但会限制为每个字符串读取的字符数,以防止缓冲区溢出。
但请注意,对于printf
情况,没有必要将字符串计算为已发布,因为您可以使用:
printf("%5s %*s %*s", "A", BUFFSIZE / 10, "B", BUFFSIZE / 10, "C");
不幸的是,scanf()
将不同的语义附加到*
格式修饰符,并且无法使用参数指定要存储的最大字符数,只能使用格式字符串中的数字,因此需要用于单独的格式化步骤。