1. 解释main函数参数及其返回值,怎么获取main的返回值,有什么作用?
2. printf是怎么实现传参的?然后,它是怎么去找到format格式里面对应的参数的?
3. 函数调用的堆栈映像是怎样的?
4. int fun()有什么结果?如果能够编译的话,会返回数值吗?返回什么数值?
解释main函数参数及其返回值,怎么获取main的返回值,有什么作用?
目前来讲,标准的main应该是
int main(int argc, char **argv /* , char **envp */)
{
return 0;
}
当内核执行C程序时(使用一个exec函数),在调用main函数前先调用一个特殊的启动例程。可执行文件将此启动例程指定为程序的起始位置(这是由连接编辑器设置的,而连接编辑器则由C编辑器调用)
main函数参数
启动例程从内核取得命令行参数和环境变量值,然后按ISO C标准传递参数给main函数
获取main返回值
main的返回值是该进程的返回码,根据该返回码获知该程序是否正常执行,或是否发生异常。
Linux下,执行 echo $? 即可获取main返回值
printf是怎么实现传参的?然后,它是怎么去找到format格式里面对应的参数的?
这个问题的深层问题:怎么实现可变参数列表?
思考问题:堆栈中的参数次序
按参数列表相反的顺序压入到堆栈中,参数列表的第1个参数便位于堆栈中这堆参数的顶部,它距离帧指针的偏移量是一个常数。事实上,任何一个参数距离帧指针的偏移量都是一个常数,这和堆栈中压入多少个参数并无关系。(回答第1个子问题)
然后,printf的第一个参数就是字符串指针,是一个常量(被双引号括起来的那部分),函数通过判断字符串里面的控制参数的个数来判断参数的个数和类型。("%d %d"就表示有两个整形参数)(回答第2个子问题)
下面是模拟一个printf的实现
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
//printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
//printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
//printf("char %c\n", c);
break;
}
va_end(ap);
}
非常类似
1. 里面一个while把参数列表里面的所有控制参数都“检索”出来,包括参数类型和个数
2. 注释掉的printf可以改变为其他输出函数(假定为系统的sys_printf)
函数调用的堆栈映像是怎样的?
被调用函数从堆栈帧指针返回,被调用函数并没有从堆栈中完全清除它的整个堆栈帧:参数还留在那里等待调用函数清除。同样,它的原因和可变参数列表有关。调用函数把参数压到堆栈上,所以只有它才知道堆栈中到底有多少个参数。因此,只有调用函数可以安全地清除它们。
int fun()有什么结果?如果能够编译的话,会返回数值吗?返回什么数值?
如果,编译器能够通过该程序编译,那么,有可能会返回2;这是编译器把某个寄存器当作“中间结果暂存器”或临时位置,并且函数放回值就放在这个寄存器里面,那么,调用函数就会从这个寄存器中获取被调用函数的返回值。
领取专属 10元无门槛券
私享最新 技术干货