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代码编译成可执行程序的过程的更多相关文章

  1. Unity 代码编译成dll 更新dll实现热更代码

    Unity 代码编译成dll 更新dll实现热更代码 实现流程 代码编译成DLL DLL打包成AssetBundle 加载AssetBundle 加载代码程序集 获取指定类 使用反射赋值 C#代码编译 ...

  2. 用gcc编译成可执行程序 (转)

    #gcc hello.c 该命令将hello.c直接生成最终二进制可执行程序a.out 这条命令隐含执行了(1)预处理.(2)汇编.(3)编译并(4)链接形成最终的二进制可执行程序.这里未指定输出文件 ...

  3. OC代码编译成c++代码 编译器命令

    xcrun -sdk iphoneos clang -arch x86_64 -rewrite-objc Person+Test.m clang -rewrite-objc -fobjc-arc -s ...

  4. python如何调用c编译好可执行程序

    python如何调用c编译好可执行程序       以下总结出几种在Python 中调用 C/C++ 代码的方法 ------------------------------------------- ...

  5. 【CLR via C#】CSC将源代码编译成托管模块

    下图展示了编译源代码文件的过程.如图所示,可用支持 CLR 的任何一种语言创建源代码文件.然后,用一个对应的编译器检查语法和分析源代码.无论选用哪一个编译器,结果都是一个托管模块(managedmod ...

  6. 用python写个简单的小程序,编译成exe跑在win10上

    每天的工作其实很无聊,早知道应该去IT公司闯荡的.最近的工作内容是每逢一个整点,从早7点到晚11点,去查一次客流数据,整理到表格中,上交给素未蒙面的上线,由他呈交领导查阅. 人的精力毕竟是有限的,所以 ...

  7. php代码编译的实现

    1.php是解析型的高级语言,zend内核使用c语言实现,有main函数,php脚本就是输入,内核处理后输出结果,内核将php脚本翻译成c程序可识别的opcode就是php的编译. c语言的编译将c代 ...

  8. Windows下使用Graalvm将Javafx应用编译成exe

    1 背景 Graalvm是Oracle推出的一款新型虚拟机,其中一个吸引人的功能是:它可以将Java代码编译成各个平台的本地代码,这些平台包括:linux.macOS.windows.iOS.andr ...

  9. Linux | GCC如何实现代码编译&&汇编&&链接过程

      正文: 每次我们程序员所写的 代码 是给程序员看的呢?还是给电脑看的?其实我们所写的代码只是我们程序员之间交流的一样特殊语言,电脑是看不懂的.那么我们如何实现人机交流呢?这就不得不请出我们我们今天 ...

随机推荐

  1. Ubuntu12.04安装到U盘里

    把linux安装到U盘里,随时随地使用自己的系统show一下不仅用起来顺手而且很方便携带.看了一些关于安装Ubuntu到U盘的资料,自己试着折腾了几次,并且成功安装了.花时间更新要保证系统是最新的就要 ...

  2. .NET牛人应该知道些什么

    任何一个使用.NET的人 1.描述线程与进程的区别? 线程(Thread)与进程(Process)二者都定义了某种边界,不同的是进程定义的是应用程序与应用程序之间的边界,不同的进程之间不能共享代 码和 ...

  3. git 使用入门

    参考教程: 廖雪峰的官方网站 MY UBUNTU 安装: sudo apt-get install git GIT 理解: 选定的目录为git的工作区.该目录下的任何改动,git都会记录为工作区的修改 ...

  4. hive删除数据

    按分区删除: ALTER TABLE test1  DROP PARTITION (dt='2016-04-29'); 删除符合条件的数据: insert overwrite table t_tabl ...

  5. 如何定位Sharepoint网站集所在的w3wp进程

     方法1.    直接开始运行,输入cmd,再输入iisapp可以列出当前所有IIS中的WebApplication所对应的w3wp.exe进程,后面都有一个进程号标识,在VS中调试的时候附加到对应进 ...

  6. 谈谈React Native环境安装中我遇到的坑

    谈谈React Native环境安装 这个坑把我困了好久,真的是接近崩溃的边缘...整理出来分享给大家,希望遇到跟我一样问题的小伙伴能尽快找到答案. 首先,这是在初始化App之后,react-nati ...

  7. strcpy和memcpy的区别(转载)

    strcpy和memcpy都是标准C库函数,它们有下面的特点.strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符. 已知strcpy函 ...

  8. openStack windows时间偏移

    openstack

  9. Thinkphp的单字母函数整理

    有人不太喜欢TP这种单字母函数,其实这也是TP的一个特色,如果理解了这些函数的作用,不管是背,还是写,都是非常方便的,接下来我们以字母顺序开始.A函数 B函数 C函数 D函数 F函数 L函数 R函数 ...

  10. 外网无法访问本地IIS站点

    自己申请了个花生壳动态域名,本来是打算在IIs上建个站点测试一下的,路由器上的端口也配置好了,把80端口指向我本机.域名也通过 ping 测试确实指向了我这里的路由器.但是用这个域名老是访问不了我这个 ...