1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# include <stdio.h>
int
main()
{
printf
(
"%s"
);
return
0;
}
cc -Wall x.c -o x
x.c: In function ‘main’:
x.c:5: warning: too few arguments
for
format
# include <stdio.h>
int
main()
{
char
* p =
"%s"
;
printf
(p);
return
0;
}
cc -Wall x.c -o x
|
int printf(const char *format, ...);
注意printf的原型,format是const char *类型,至于传给它的是"%s"或者p(char * p = "%s")都无所谓,因为它们都是const char *类型的(p的类型char *能兼容/转成const char *)
一般来说,%specifier意味后面有对应的一个参数,这里的%s即是一个specifier,后面应该有个参数的。
对于第一种情况,format是个字母量/常量,编译器在编译的时候就能检查出这种情况(编译时),所以它很聪明的给出了warning;第二种情况,format是个变量p,编译器就不知道当运行到printf的时候,它的内容是是什么(因为内容可以是动态生成的,即运行时),而很不幸,printf的原型是个变参的函数,除了第一个参数确定,后面的参数都不确定,编译器只认为有一个参数,没有报任何warning(简言之,做不了检查)。
现在问题就变成了,应该有两个参数来调用printf的,类似于
printf("%s", "hello, world");或者
char * p = "%s";
char * s = "hello, world";
printf(p, s);
现在只有一个参数来调用printf,即
printf("%s");或者
printf(p);
会发生什么情况?
这种情况讨论过很多次了,关键就在于函数调用的汇编层面,发生了什么。
在汇编层面,函数的调用是先压参数入栈,然后调用函数入口,函数内部从栈上获得参数,进行运算。
现在参数个数错了,少压了一个,进入函数后函数为了获得参数会怎么办?
只能从栈上错误的位置捞错误的值作为参数运算 ,结果怎样都不奇怪。