可能回答问题
- 解释main函数参数及其返回值,怎么获取main的返回值,有什么作用?
- printf是怎么实现传参的?然后,它是怎么去找到format格式里面对应的参数的?
- 函数调用的堆栈映像是怎样的?
- int fun(){int a=1,b=1, x; x=a+b: return;}有什么结果?如果能够编译的话,会返回数值吗?返回什么数值?
参考文章
- C和指针,18章(讲解非常好),C源码与汇编,结合讲解,配合堆栈的映像图
- APUE,7章
解释main函数参数及其返回值,怎么获取main的返回值,有什么作用? 目前来讲,标准的main应该是 int main(int argc, char **argv ) { 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': s = va_arg(ap, char *); //printf("string %s\n", s); break; case 'd': d = va_arg(ap, int); //printf("int %d\n", d); break; case 'c': c = (char) va_arg(ap, int); //printf("char %c\n", c); break; } va_end(ap); } 非常类似
- 里面一个while把参数列表里面的所有控制参数都“检索”出来,包括参数类型和个数
- 注释掉的printf可以改变为其他输出函数(假定为系统的sys_printf)
函数调用的堆栈映像是怎样的?
被调用函数从堆栈帧指针返回,被调用函数并没有从堆栈中完全清除它的整个堆栈帧:参数还留在那里等待调用函数清除。同样,它的原因和可变参数列表有关。调用函数把参数压到堆栈上,所以只有它才知道堆栈中到底有多少个参数。因此,只有调用函数可以安全地清除它们。
int fun(){int a=1,b=1, x; x=a+b: return;}有什么结果?如果能够编译的话,会返回数值吗?返回什么数值? 如果,编译器能够通过该程序编译,那么,有可能会返回2;这是编译器把某个寄存器当作“中间结果暂存器”或临时位置,并且函数放回值就放在这个寄存器里面,那么,调用函数就会从这个寄存器中获取被调用函数的返回值。