微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > gcc的几个妙用

gcc的几个妙用

时间:12-01 来源:互联网 点击:

eporting instructions, please see:
.

从上面的结果可以知道基本的用法。

但是还是有几个需要注意的地方,这也是我们学习gcc时不经常使用,但又非常有用的几个用法。

1、采用gcc实现预编译,预编译可以实现代码的检查,特别是宏定义的检查,通过预编译检查实际的代码是否出错,这是非常有用的检查方式。

由于预编译以后宏定义被扩展了,这时对源码的分析就能找出代码宏定义等是否存在错误,特别时一些不容易发现的错误。

基本的实现形式为:gcc -E file.c > file.pre.c

[gong@Gong-Computer Example]$ vi main.c

采用重定向的方式改变输出流,便于检查错误所在。
[gong@Gong-Computer Example]$ gcc -E main.c > main.pre.c

[gong@Gong-Computer Example]$ vi main.pre.c

从上面的结果可以发现我们的宏已经实现了扩展。通过分析宏的扩展可以分析代码是否正确。
比如我将宏定义max(x,y)改写为max (x,y)就会出现下面的结果。如下图所示。

从856行的结果我们可以知道,上面的代码并不是我们需要的情况,这说明我们的代码存在问题,从而实现了宏定义的检测。这是非常有用的一种检测方式。

2、产生镜像文件

基本的实现方法是:注意Wl逗号后面跟着需要传递的参数,逗号后面不能存在空格,否则出现错误。

gcc -Wl,-Map=file.map file.c -o target

关于选项-Wl的使用可以参考help,这是我的一个截图

从上面说明可以知道-Wl用于传递参数给链接器。当然也有传递给汇编器和预编译的选项。

通过上面的选项可以得到一个镜像文件,通过打开镜像文件来程序的结构。

[gong@Gong-Computer Example]$ gcc -Wl,-Map=main.map main.c -o main.exe
[gong@Gong-Computer Example]$ vi main.map

上面只是其中的一部分,还有很多的内容。其中这些内容指出了程序的基本分布情况。

3、汇编程序

汇编语言是不可避免要学习的设计语言,但是很多时候并不需要完全手动的编写汇编语言,我们可以采用gcc实现一段程序的汇编形式,只需要选择正确的选项即可。

gcc -S file.c

实现如下:

[gong@Gong-Computer Example]$ gcc -S main.c
[gong@Gong-Computer Example]$ vi main.s

从上面的代码就知道了基本的汇编形式,当然也可以自己设计,但是该选项简化了汇编语言的设计。

4、在gcc中函数库,链接库的调用,这是比较难以掌握和容易出错的地方。

在静态编译的情况下:

gcc file.c -o file -Llibpath -llibname

gcc中-L主要是指明函数库的查找目录,-L后紧跟着目录而不是文件。-l后面紧跟着需要连接的库名,需要主要的是静态库通常是以 libfile.a命名,这时-l后的库名只能是file,而不是libfile.a。这是需要注意的。一般情况下总是将-l放在最后。但是需要注意的是各个库之间的依赖关系。依赖关系没有搞清楚也会导致编译出现错误。

下面的代码如下:

  1. foo.c

  2. 1 #include
  3. 2
  4. 3
  5. 4 extern void bar();
  6. 5
  7. 6 void foo()
  8. 7{
  9. 8 printf("This is foo ().");
  10. 9
  11. 10 bar();
  12. 11}

bar.c

1 #include
2
3 void bar()
4 {
5 printf( " This is bar (). ");
6 }
7

main.c

1 extern void foo();
2
3 int main()
4 {
5 foo();
6
7 return 0;
8 }
~

简要的介绍一些静态库的创建方式。

首先需要注意的时静态编译是指将一些库函数编译到程序中,这样会增加程序的大小。动态库则是在运行过程中添加到程序中,这样可以减小程序的大小。两种方式都有各自的优势。

静态库的创建:

gcc -c foo.c -o foo.o

gcc -c bar.c -o bar.o

创建的基本过程就是采用归档函数实现。

ar csr libfoo.a foo.o

ar csr libbar.a bar.o

从上面的程序我们可以知道foo程序依赖bar程序,而main程序则依赖foo程序,所以这样就形成了一定的关系,一般来说只有将依赖的库函数写在最右边才能保证其他的库函数依赖该库函数。

[gong@Gong-Computer test]$ gcc -o main main.c -L. -lbar -lfoo
./libfoo.a(foo.o): In function `foo:
foo.c:(.text+0x13): undefined reference to `bar
collect2: ld returned 1 exit status

[gong@Gong-Computer test]$ gcc -o main main.c -L. -lfoo -lbar
以上的两个编译过程只是存在一个差异就是库的摆放顺序存在差别,第一种情况下由于foo依赖bar,而bar库不能被foo调用,因此出错。而第二种则满足foo依赖bar,main依赖foo的关系。其中的-L.表示库函数的搜索目录为当前目录。也可以换成其他的目录。

因此在gcc中添加库时,需要注意库名和库的顺序,最好采用一定的依赖关系图分析实现。具体的就要我们在设计程序时自己的考虑各个库函数之间的关系。

至于动态库的创建可以采用gcc实现。其中的-shared就是表明了

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top