C代码编译成可执行程序的过程
C代码通过编译器编译成可执行代码,经历了四个阶段,依次为:预处理、编译、汇编、链接。
接下来详细讲解各个阶段
一、预处理
1、任务:进行宏定义展开、头文件展开、条件编译,不检查语法。
2、命令:gcc -E [源文件] -o [预处理文件]
3、案例:用gcc编译器预处理demo1.c代码,预处理后的文本放到demo1.i中。(gcc -E demo1.c -o demo1.i)
demo1.c代码如下:
- #include <stdio.h>
- #define add(a, b) (a + b)
- #define sub(a, b) (a - b)
- int main(void)
- {
- int a, b, c, d;
- #ifndef __cplusplus
- a = b = c = d = ;
- #else
- a = b = c = d = ;
- #endif
- printf("num = %d\n", sub(add(a, b), add(c, d)));
- return ;
- }
demo1.c
生成的demo1.i代码如下:
- # "demo.c"
- # "<command-line>"
- # "/usr/include/stdc-predef.h"
- # "<command-line>"
- 此处省略800行...
- extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
- # "/usr/include/stdio.h"
- # "demo.c"
- int main(void)
- {
- int a, b, c, d;
- a = b = c = d = ;
- printf("num = %d\n", ((a + b) - (c + d)));
- return ;
- }
demo1.i
通过案例可以发现:#define宏定义、stdio.h头文件、#ifdef条件编译都被替换了,并且你还可以故意写一句有语法错误的代码,但是却不会报错。由于stdio.h头文件长达800多行,因此在demo1.i中只截取开头和结尾的几行。
二、编译
1、任务:检查语法,将预处理过的文件编译生成汇编文件。
2、命令:gcc -S [源文件] -o [汇编文件]
3、案例;用gcc编译器编译demo2.c代码,编译后的汇编代码放到demo2.s中。(gcc -S demo2.c -o demo2.s)
demo2.c代码如下:
- #include <stdio.h>
- int main(int argc, char *argv[])
- {
- printf("hello world\n");
- return ;
- }
demo2.c
生成的demo2.s代码如下:
- .file "demo2.c"
- .section .rodata
- .LC0:
- .string "hello world"
- .text
- .globl main
- .type main, @function
- main:
- .LFB0:
- .cfi_startproc
- pushq %rbp
- .cfi_def_cfa_offset
- .cfi_offset , -
- movq %rsp, %rbp
- .cfi_def_cfa_register
- subq $, %rsp
- movl %edi, -(%rbp)
- movq %rsi, -(%rbp)
- movl $.LC0, %edi
- call puts
- movl $, %eax
- leave
- .cfi_def_cfa ,
- ret
- .cfi_endproc
- .LFE0:
- .size main, .-main
- .ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
- .section .note.GNU-stack,"",@progbits
demo.s
通过案例可以看出,我们写的c代码被编译成了汇编代码。故意写错一个语法点,编译器将报错。
三、汇编
1、任务:将汇编文件生成目标文件(2进制文件)。
2、命令:gcc -s [源文件] -o [目标文件]
3、案例:用gcc编译器汇编demo3.c代码,编译后的二进制代码放到demo3.o中。(gcc -c demo3.c -o demo3.o)
demo3.c代码如下:
- #include <stdio.h>
- int main(int argc, char *argv[])
- {
- printf("hello world\n");
- return ;
- }
demo3.c
生成的demo3.o代码如下:
通过汇编阶段,文本代码变成了二进制代码,也就是计算机可以识别的代码。c语言中,二进制代码文件是以.o为后缀名的。
四、链接
1、任务:找到依赖的库文件,将目标文件链接为可执行程序。
2、命令:gcc -c [目标文件] -o [可执行程序] -l[动态库名]
3、案例:通过gcc编译器让demo4链接自己制作的libadd.so动态库,并把demo4编译成可执行程序。gcc demo4.c -o demo4 -L./ -ladd
demo4.c代码如下:
- #include <stdio.h>
- #include "add.h"
- int main(int argc, char *argv[])
- {
- printf("add = %d\n", add(, ));
- return ;
- }
demo4.c
通过file命令查看可执行程序的信息:
运行结果:add = 2
还可以通过“size [可执行程序]”命令,来查看程序的text段、data段、bss段的大小。
在程序还没运行前,我们是可以确定它的text段、data段、bss段的大小。
C代码编译成可执行程序的过程的更多相关文章
- Unity 代码编译成dll 更新dll实现热更代码
Unity 代码编译成dll 更新dll实现热更代码 实现流程 代码编译成DLL DLL打包成AssetBundle 加载AssetBundle 加载代码程序集 获取指定类 使用反射赋值 C#代码编译 ...
- 用gcc编译成可执行程序 (转)
#gcc hello.c 该命令将hello.c直接生成最终二进制可执行程序a.out 这条命令隐含执行了(1)预处理.(2)汇编.(3)编译并(4)链接形成最终的二进制可执行程序.这里未指定输出文件 ...
- OC代码编译成c++代码 编译器命令
xcrun -sdk iphoneos clang -arch x86_64 -rewrite-objc Person+Test.m clang -rewrite-objc -fobjc-arc -s ...
- python如何调用c编译好可执行程序
python如何调用c编译好可执行程序 以下总结出几种在Python 中调用 C/C++ 代码的方法 ------------------------------------------- ...
- 【CLR via C#】CSC将源代码编译成托管模块
下图展示了编译源代码文件的过程.如图所示,可用支持 CLR 的任何一种语言创建源代码文件.然后,用一个对应的编译器检查语法和分析源代码.无论选用哪一个编译器,结果都是一个托管模块(managedmod ...
- 用python写个简单的小程序,编译成exe跑在win10上
每天的工作其实很无聊,早知道应该去IT公司闯荡的.最近的工作内容是每逢一个整点,从早7点到晚11点,去查一次客流数据,整理到表格中,上交给素未蒙面的上线,由他呈交领导查阅. 人的精力毕竟是有限的,所以 ...
- php代码编译的实现
1.php是解析型的高级语言,zend内核使用c语言实现,有main函数,php脚本就是输入,内核处理后输出结果,内核将php脚本翻译成c程序可识别的opcode就是php的编译. c语言的编译将c代 ...
- Windows下使用Graalvm将Javafx应用编译成exe
1 背景 Graalvm是Oracle推出的一款新型虚拟机,其中一个吸引人的功能是:它可以将Java代码编译成各个平台的本地代码,这些平台包括:linux.macOS.windows.iOS.andr ...
- Linux | GCC如何实现代码编译&&汇编&&链接过程
正文: 每次我们程序员所写的 代码 是给程序员看的呢?还是给电脑看的?其实我们所写的代码只是我们程序员之间交流的一样特殊语言,电脑是看不懂的.那么我们如何实现人机交流呢?这就不得不请出我们我们今天 ...
随机推荐
- 高斯模糊算法的 C++ 实现
2008 年在一个 PS 讨论群里,有网友不解 Photoshop 的高斯模糊中的半径是什么含义,因此当时我写了这篇文章: 对Photoshop高斯模糊滤镜的算法总结: 在那篇文章中,主要讲解了高斯模 ...
- Linux 任务计划
一.配置cron实现自动化 使用cron实现任务自动化可以通过修改/etc/crontab文件以及使用crontab命令实现,其结果是一样的. 1./etc/crontab文件实现自动化 cron守护 ...
- Java应用程序访问网络资源--HttpClient
HttpClient的最本质的功能是执行HTTP方法.一个HTTP方法的执行涉及到一个或几个HTTP请求/ HTTP响应的交流,通常由HttpClient的内部处理.用户预计将提供一个请求对象来执行和 ...
- Xcode 8 在XIB中布局View尺寸1000*1000
Xcode 8 中XIB布局变动,在界面未展示之前,所有的View的布局都会给一个1000*1000的初始值,查看视图层级可以看到View拖得很长, 有时候我们在ViewDidLoad中布局的时候会使 ...
- java上传xls文件
using System; using System.Collections.Generic; using System.Web; using System.Web.UI; using System. ...
- python迭代器,生成器,装饰器,context模块
迭代器iteration 是访问集合元素的一种方式,只能往前不能往后迭代器的特点:1,访问者不需要关注迭代器内部结构,只需通过next()不断取下一个内容2,访问不能回退3,循环较大数据集合时,省内存 ...
- http://blog.csdn.net/shawnkong/article/details/52045894
http://blog.csdn.net/shawnkong/article/details/52045894
- arp命令
地址解析协议ARP用于将IP地址解析成MAC地址.当把数据包从一个计算机发送到另一个计算机的时候,计算机或路由器使用ARP请求来确定下一跳的MAC地址. MAC地址用于按跳发送数据包,直到达到最终目的 ...
- 如果客户端禁用cookie,session还能使用吗?
记得在以前找工作的时候,可多次被问到如果客户端被禁用cookie,session还能使用吗? 今天终于找到了相关的答案:我们来看一下: session是在服务器段保持会话数据的一种方法,对应的cook ...
- 实现SQL Server 2008 Reporting Services匿名访问报表有两种方法
一.通过修改SQL Server 2008的配置文件,去掉Windows的验证. 1.首先我们找到SQL安装目录下的两个Web.config配置文件,默认安装目录分别是(C:\Program File ...