- 1、本文档共8页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 5、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 6、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 7、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 8、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
C语言printf()函数深入分析
?说 起编程语言,C语言大家再熟悉不过。说起最简单的代码,Helloworld更是众所周知。一条简单的printf语句便可以完成这个简单的功能,可是 printf背后到底做了什么事情呢?可能很多人不曾在意,也或许你比我还要好奇!那我们就聊聊printf背后的故事。
一、printf的代码在哪里?
显然,Helloworld的源代码需要经过编译器编译,操作系统的加载才能正确执行。而编译器包含预编译、编译、汇编和链接四个步骤。
#includestdio.h
int main()
{
??? printf(Hello World !\n);
??? return 0;
}
首先,预编译器处理源代码中的宏,比如#include。预编译结束后,我们发现printf函数的声明。
$/usr/lib/gcc/i686-linux-gnu/4.7/cc1 -E -quiet?main.c -o main.i
# 1 main.c
# 1 命令行
# 1 main.c
...
extern int printf (const char *__restrict __format, ...);
...
int main()
{
?printf(Hello World!\n);
?return 0;
}
然后编译器将高级语言程序转化为汇编代码。
$/usr/lib/gcc/i686-linux-gnu/4.7/cc1 -fpreprocessed -quiet?main.i -o main.s
??? .file????? main.c
??? .section?? .rodata
.LC0:
??? .string??? Hello World!
??? .text
??? .globl???? main
??? .type????? main, @function
main:
??? pushl????? %ebp
??? movl?????? %esp,? %ebp
??? andl?????? $-16,? %esp
??? subl?????? $16,?? %esp
??? movl?????? $.LC0, (%esp)
??? call?????? puts
??? movl?????? $0,??? %eax
??? leave
??? ret
??? .size????? main, .-main
...
我 们发现printf函数调用被转化为call puts指令,而不是call printf指令,这好像有点出乎意料。不过不用担心,这是编译器对printf的一种优化。实践证明,对于printf的参数如果是以\n结束的纯 字符串,printf会被优化为puts函数,而字符串的结尾\n符号被消除。除此之外,都会正常生成call printf指令。
如果我们仍希望通过printf调用Hello World !\n的话,只需要按照如下方式修改即可。不过这样做就不能在printf调用结束后立即看到打印字符串了,因为puts函数可以立即刷新输出缓冲区。我们仍然使用puts作为例子继续阐述。
??? .section?? .rodata
.LC0:
??? .string??? hello world!\n
??? ...
??? call?????? printf
...
接下来,汇编器开始工作。将汇编文件转化为我们不能直接阅读的二进制格式——可重定位目标文件,这里我们需要gcc工具包的objdump命令查看它的二进制信息。可是我们发现call puts指令里保存了无效的符号地址。
$as -o main.o main.s
$objdump –d main.o
main.o:???? 文件格式 elf32-i386
Disassembly of section .text:main:
?? 0:? 55?????????????????? ? push?? %ebp
?? 1:? 89 e5??????????????? ? mov??? %esp,%ebp
?? 3:? 83 e4 f0???????????? ? and??? $0xfffffff0,%esp
?? 6:? 83 ec 10???????????? ? sub??? $0x10,%esp
?? 9:? c7 04 24 00 00 00 00 ??? movl?? $0x0,(%esp)
? 10:? e8 fc ff ff ff?????? call?? 11 main+0x11
? 15:? b8 00 00 00 00?????? mov??? $0x0,%eax
? 1a:? c9????????????
您可能关注的文档
最近下载
- Unit1《实用商务英语写作教程》作者董晓波—教学课件.ppt VIP
- 中西医结合诊所规章制度大全.docx VIP
- (2025年)抗菌药物临床应用知识培训考试题库(附答案).docx VIP
- DLT 5044-2014 电力工程直流电源系统设计技术规程.docx
- 《联合国教科文:教师人工智能能力框架》--中文版.docx
- OpenHarmony应用开发认证考试题库大全-中(多选题汇总).docx
- 山东省济南市历城区2023-2024学年四年级下学期期末考试数学试题 附答案.pdf VIP
- 机封培训课件.pptx VIP
- 2023年7月黑龙江省普通高中学业水平合格性考试物理真题试卷含答案.docx VIP
- 中外新闻传播史考题及答案.pdf VIP
文档评论(0)