转自:http://blog.csdn.net/eastmoon502136/article/details/8190262/

上篇文章,知道了,C代码编译后存放在内存中的位置,那么C代码的整个编译过程又是怎样的呢?一条命令gcc hello.c就可以编译成可执行程序a.out,然后./a.out之后就可以执行hello.c这个程序的代码了。下面的文章分析的不错,就整理了下。

hello.c:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. printf(“Hello World\n”);
  5. return 0;
  6. }

实际上gcc hello.c可以分解为4个步骤,分别是预处理(Preprocess),编译(Compilation),汇编(Assembly)和链接(Linking)。

一、预处理

预处理过程主要读取c源程序,对伪指令和特殊符号进行处理。包括宏,条件编译,包含的头文件,以及一些特殊符号。基本上是一个replace的过程。

  1. gcc –E hello.c –o hello.i

以下为预处理后的输出文件hello.i的内容

  1. # 1"hello.c"
  2. # 1"<built-in>"
  3. # 1"<command-line>"
  4. # 1"hello.c"
  5. # 1 "/usr/include/stdio.h"1 3 4
  6. # 28"/usr/include/stdio.h" 3 4
  7. /***** 省略了部分内容,包括stdio.h中的一些声明及定义  *****/
  8. # 2"hello.c" 2
  9. int main()
  10. {
  11. printf("Hello World\n");
  12. return 0;
  13. }

预处理过程主要处理规则如下:

1、将所有的#define删除,并且展开所有的宏定义;

2、处理所有条件编译指令,如#if,#ifdef等;

3、处理#include预编译指令,将被包含的文件插入到该预编译指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。

4、删除所有的注释//和 /**/;

5、添加行号和文件标识,如#2 “hello.c” 2,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;

6、保留所有的#pragma编译器指令,因为编译器须要使用它们;

二、编译

编译过程通过词法和语法分析,确认所有指令符合语法规则(否则报编译错),之后翻译成对应的中间码,在Linux中被称为RTL(Register
Transfer
Language),通常是平台无关的,这个过程也被称为编译前端。编译后端对RTL树进行裁减,优化,得到在目标机上可执行的汇编代码。gcc采用as作为其汇编器,所以汇编码是AT&T格式的,而不是Intel格式,所以在用gcc编译嵌入式汇编时,也要采用AT&T格式。

  1. gcc –S hello.i –o hello.s

以下为编译后的输出文件hello.s的内容

  1. .file  "hello.c"
  2. .section    .rodata
  3. .LC0:
  4. .string      "HelloWorld"
  5. .text
  6. .globl main
  7. .type         main, @function
  8. main:
  9. pushl         %ebp
  10. movl          %esp, %ebp
  11. andl $-16, %esp
  12. subl  $16, %esp
  13. movl          $.LC0, (%esp)
  14. call   puts
  15. movl          $0, %eax
  16. leave
  17. ret
  18. .size main, .-main
  19. .ident        "GCC: (GNU)4.4.0 20090506 (Red Hat 4.4.0-4)"
  20. .section   .note.GNU-stack,"",@progbits

三、汇编

汇编器是将汇编代码转变成机器可以执行的命令,每一个汇编语句几乎都对应一条机器指令。汇编相对于编译过程比较简单,根据汇编指令和机器指令的对照表一一翻译即可。

  1. gcc –c hello.c –o hello.o

由于hello.o的内容为机器码,不能以文本形式方便的呈现。

四、链接

链接器ld将各个目标文件组装在一起,解决符号依赖,库依赖关系,并生成可执行文件。

  1. ld –static crt1.o crti.o crtbeginT.ohello.o –start-group –lgcc –lgcc_eh –lc-end-group crtend.o crtn.o

(省略了文件的路径名)。

当然链接的时候还会用到静态链接库,和动态连接库。静态库和动态库都是.o目标文件的集合。

静态库是在链接过程中将相关代码提取出来加入可执行文件的库(即在链接的时候将函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中),ar只是将一些别的文件集合到一个文件中。可以打包,当然也可以解包。

  1. ar -v -q  test.a test.o

上面指令可以生成静态链接库test.a

动态库在链接时只创建一些符号表,而在运行的时候才将有关库的代码装入内存,映射到运行时相应进程的虚地址空间。如果出错,如找不到对应的.so文件,会在执行的时候报动态连接错(可用LD_LIBRARY_PATH指定路径)。用file
test.so可以看到test.so是shared object的ELF文件。

  1. gcc -sharedtest.so test.o

上面指令可以生成动态连接库test.so

好了,整个编译过程就如上所示了,那么对于gcc还有一些编译的选项的。具体如下:

GCC编译选项

1. -c

编译产生对象文件(*.obj)而不链接成可执行文件,当编译几个独立的模块,而待以后由链接程序把它们链接在一起时,就可以使用这个选项,如:

  1. gcc -c hello.c ===> hello.o
  2. gcc hello.o

2. -o

允许用户指定输出文件名,如

  1. gcc hello.c -o hello.o
  2. or
  3. gcc hello.c -o hello

3. -g

指明编译程序在编译的输出中应产生调试信息.这个调试信息使源代码和变量名引用在调试程序中或者当程序异常退出后在分析core文件时可被使用.

4. -D

允许从编译程序命令行定义宏符号

一共有两种情况:一种是用-DMACRO,相当于在程序中使用#define MACRO,另一种是用-DMACRO=A,相当于程序中的#define MACRO A.如对下面这代码:

  1. #ifdef DEBUG
  2. printf("debugmessage\n");
  3. #endif

编译时可加上-DDEBUG参数,执行程序则打印出编译信息

5. -I

可指定查找include文件的其他位置.例如,如果有些include文件位于比较特殊的地方,比如/usr/local/include,就可以增加此选项如下:

  1. gcc -c -I/usr/local/include -I/opt/include hello.c

此时目录搜索会按给出的次序进行.

6. -E

这个选项是相对标准的,它允许修改命令行以使编译程序把预先处理的C文件发到标准输出,而不实际编译代码.在查看C预处理伪指令和C宏时,这是很有用的.可能的编译输出可重新定向到一个文件,然后用编辑程序来分析:

  1. gcc -c -E hello.c >cpp.out

此命令使include文件和程序被预先处理并重定向到文件cpp.out.以后可以用编辑程或者分页命令分析这个文件,并确定最终的C语言代码看起来如何.

7. -O

优化选项,这个选项不是标准的

-O和 -O1指定1级优化

-O2 指定2级优化

-O3 指定3级优化

-O0指定不优化

gcc -c O3 -O0 hello.c

当出现多个优化时,以最后一个为准!!

8. -Wall

以最高级别使用GNU编译程序,专门用于显示警告用!!

  1. gcc -Wall hello.c

9. -L

指定连接库的搜索目录,-l(小写L)指定连接库的名字

  1. gcc main.o -L/usr/lib -lqt -o hello

10.-share   

此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库

11.-static  

此选项将禁止使用动态库,所以,编译出来的东西,一般都很大,也不需要什么动态连接库

12.-fPIC

表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

和菜鸟一起学linux之V4L2摄像头应用流程【转】的更多相关文章

  1. linux之V4L2摄像头应用流程【转】

    本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11486907 对于v4l2,上次是在调试收音机驱动的时候用过,其他也就只是用i2c配置一 ...

  2. Linux 下V4l2摄像头采集图片,实现yuyv转RGB,RGB转BMP,RGB伸缩,jpeglib 库实现压缩RGB到内存中,JPEG经UDP发送功(转)

    ./configure CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld --host=arm-linux --prefix=/usr/loca ...

  3. C语言高级应用---操作linux下V4L2摄像头应用程序

    我们都知道,想要驱动linux下的摄像头,其实很简单,照着V4L2的手册一步步来写,很快就可以写出来,但是在写之前我们要注意改变系统的一些配置,使系统支持framebuffer,在dev下产生fb0这 ...

  4. C语言高级应用---操作linux下V4L2摄像头应用程序【转】

    转自:http://blog.csdn.net/morixinguan/article/details/51001713 版权声明:本文为博主原创文章,如有需要,请注明转载地址:http://blog ...

  5. 和菜鸟一起学linux总线驱动之初识spi驱动数据传输流程【转】

    转自:http://blog.csdn.net/eastmoon502136/article/details/7921846 对于SPI的一些结构体都有所了解之后呢,那么再去瞧瞧SPI的那些长见的操作 ...

  6. 和菜鸟一起学linux总线驱动之i2c死锁问题

    不知不觉中已经有好几个月没有写点东西了,懒了就是懒了,说是忙着想把产品做得更好,都是借口,每天花一点时间来写点东西确实很不错,自己也坚持了很久很久,只不过今年以来,发现提高不是很大,能写的东西好少好少 ...

  7. 和菜鸟一起学linux之upnp协议的学习记录

    UPnP全名是Universal Plug and Play,主要是微软在推行的一个标准.简单的来说,UPnP 最大的愿景就是希望任何设备只要一接上网络,所有在网络上的设备马上就能知道有新设备加入,这 ...

  8. 和菜鸟一起学linux之DBUS基础学习记录

    D-Bus三层架构 D-Bus是一个为应用程序间通信的消息总线系统, 用于进程之间的通信.它是个3层架构的IPC 系统,包括: 1.函数库libdbus ,用于两个应用程序互相联系和交互消息. 2.一 ...

  9. 和菜鸟一起学linux内核源码之基础准备篇

    来源:http://blog.csdn.net/eastmoon502136/article/details/8711104 推荐阅读:linux内核源码最初版linux内核源代码,简单易懂,适合初学 ...

随机推荐

  1. [CodeForces950C]Zebras

    Description 题目地址: Codeforces 题意:给你一串只含01的字符串,判断能否将字符串分为k个子序列,使得子序列满足以下条件: 开头和结尾都是0 相邻的2个数是01或者10 如0, ...

  2. C++封装的全部总结

    类 类是对现实生活中一类具有共同特征的事物的抽象 类是面向对象程序设计实现信息封装的基础. 类是一种用户定义类型,也称类类型. 类的实例称为对象. 类的实质是一种数据类型 面向对象原则 以对象为中心, ...

  3. 笔记-scrapy与twisted

    笔记-scrapy与twisted Scrapy使用了Twisted作为框架,Twisted有些特殊的地方是它是事件驱动的,并且比较适合异步的代码. 在任何情况下,都不要写阻塞的代码.阻塞的代码包括: ...

  4. java实时监听日志写入kafka(多目录)

    目的 实时监听多个目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) ...

  5. Android 网络通用类 NetUtil

    1.整体分析 1.1.源代码如下,可以直接Copy. public class NetUtil { /** * 用户是否连接网络 * * @param context Context */ publi ...

  6. AD9 设置网络标号作用域

    http://blog.sina.com.cn/s/blog_99c8ec600102uxul.html 1.版本:Altium Designer 10 2.原因:在进行多原理图设计时, 不同原理图之 ...

  7. svn TortoiseSVN 回滚版本

    原文链接: http://keenwon.com/1072.html SVN是一个版本管理工具,在工作中经常使用,尤其是多人合作开发的时候,版本管理显得更加重要.需要使用回退的场景往往都比较" ...

  8. linux驱动学习_1

    目前项目需要,需要做linux驱动了,记录一下 学习驱动,大家一定都会写一个hello world代码,网上也有很多范例,但是记录一下遇到的问题. 1.make之后,使用insmod加载,终端没有打印 ...

  9. python 学习分享-rabbitmq

    一.RabbitMQ 消息队列介绍 RabbitMQ也是消息队列,那RabbitMQ和之前python的Queue有什么区别么? py 消息队列: 线程 queue(同一进程下线程之间进行交互) 进程 ...

  10. Leetcode 671.二叉树中第二小的节点

    二叉树中第二小的节点 给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0.如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值. 给出这样的一个二叉树 ...