2、GCC编译器的使用

GCC编译器是一个非常强大和流行的C编译器,适用于各种Linux发行版。本文解释了一些流行的GCC编译器选项。

GCC编译器选项

1.指定输出可执行文件名称

在最基本的形式中,gcc编译器可以用作:

gcc main.c

上述命令执行完整的编译过程并输出名为a.out的可执行文件。

使用选项-o,如下所示,指定可执行文件的输出文件名。

gcc main.c -o main

上面的命令会产生一个名为“main”的输出文件。

2.启用通过-Wall选项设置的所有警告

该选项启用GCC中的所有警告。

#include<stdio.h>  
  
int main(void)  
{  
   int i;  
   printf("\n The Geek Stuff [%d]\n", i);  
   return 0;  
}

$ gcc -Wall main.c -o main

会将警告显示如下:

3.只用-E选项生成预处理器输出

预处理阶段的输出可以使用-E选项生成。

$ gcc -E main.c> main.i

gcc命令在stdout上产生输出,所以你可以在任何文件中重定向输出。在我们的情况(上面)中,main.i文件将包含预处理的输出。

4.使用-S选项仅生成汇编代码

装配级输出可以使用-S选项生成。

gcc -S main.c> main.s

在这种情况下,文件main.s将包含程序集输出。

5.仅使用-C选项生成编译的代码

为了只产生编译的代码(没有任何链接),使用-C选项。

gcc -C main.c

上面的命令会生成一个main.o文件,其中包含机器级代码或编译代码。

6.使用-save-temps函数生成所有中间文件

选项-save-temps可以完成上面例子4,5和6中所做的所有工作。通过这个选项,在编译的所有阶段输出都存储在当前目录中。请注意,这个选项也会生成可执行文件。

例如 :

$ gcc -save-temps main.c

$ ls
a.out main.c main.i main.o main.s

所以我们看到所有的中间文件以及最终的可执行文件都是在输出中生成的。

7.使用-l选项与共享库链接

选项-l可用于链接共享库。例如:

gcc -Wall main.c -o main -lCPPfile

上面提到的gcc命令将代码main.c和共享库libCPPfile.so链接起来,生成最终的可执行文件“main”。

8.使用-fPIC选项创建与位置无关的代码

在创建共享库时,应该生成位置独立的代码。这有助于共享库被加载为任何地址,而不是一些固定的地址。为此使用-fPIC选项。

例如,以下命令从源文件Cfile.c中创建共享库libCfile.so:

$ gcc -c -Wall -Werror -fPIC Cfile.c
$ gcc -shared -o libCfile.so Cfile.o

所以我们看到选项-fPIC用于创建共享库。

9.使用-V选项打印所有执行的命令

选项-v可用于提供编译源文件时gcc所执行的所有步骤的详细信息。

例如 :

$ gcc -Wall -v main.c -o main  
Using built-in specs.  
COLLECT_GCC=gcc  
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.6/lto-wrapper  
Target: i686-linux-gnu  
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.3-1ubuntu5' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu  
Thread model: posix  
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)  
...  
...  
...  

所以我们看到详细的信息是在输出中产生的。

10.使用-ansi选项启用对ISO C89程序的支持

通过-ansi选项启用对ISO C89风格的支持。

考虑下面的代码:

#include<stdio.h>  
  
int main(void)  
{  
  // Print the string  
   printf("\n The Geek Stuff\n");  
   return 0;  
}  

如果上面的代码是用-ansi选项编译的,那么gcc会产生一个错误,因为ISO C89风格不允许C ++注释。

这是输出:

$ gcc -Wall -ansi main.c -o main  
main.c: In function ”main“:  
main.c:5:3: error: expected expression before ‘/’ token  

所以我们看到gcc抛出了与评论风格有关的错误。

11.使用-funsigned-char选项将char解释为无符号字符

通过这个选项,char类型被视为无符号类型。

这里是一个例子:

#include<stdio.h>  
  
int main(void)  
{  
  char c = -10;  
  // Print the string  
   printf("\n The Geek Stuff [%d]\n", c);  
   return 0;  
}  

当上面的代码用funsigned-char选项编译时,输出如下:

$ gcc -Wall -funsigned-char main.c -o main  
$ ./main  
  
 The Geek Stuff [246]  

所以我们看到字符确实被视为未签名。

12.使用-fsigned-char选项将char解释为signed char

这与我们在上面(12)中讨论的相反。使用这个标志,char变量被视为有符号的。

这里是一个例子:

$ gcc -Wall -fsigned-char main.c -o main
$ ./main

输出证实char被视为已签名。

13.使用-D选项使用编译时宏

编译器选项D可以用来在代码中定义编译时间宏。

这里是一个例子:

#include<stdio.h>  
  
int main(void)  
{  
#ifdef MY_MACRO  
  printf("\n Macro defined \n");  
#endif  
  char c = -10;  
  // Print the string  
   printf("\n The Geek Stuff [%d]\n", c);  
   return 0;  
}  

编译器选项-D可用于从命令行定义宏MY_MACRO。

$ gcc -Wall -DMY_MACRO main.c -o main  
$ ./main  
  
 Macro defined   
  
 The Geek Stuff [-10]  

  

14.使用-Werror选项将警告转换为错误

通过这个选项,gcc可以报告的任何警告都会被转换成错误。

这里是一个例子:

#include<stdio.h>  
  
int main(void)  
{  
  char c;  
  // Print the string  
   printf("\n The Geek Stuff [%d]\n", c);  
   return 0;  
}  

上面的代码的编译应该生成与未定义的变量c有关的警告,这应该通过使用-Werror选项转换为错误。

$ gcc -Wall -Werror main.c -o main  
main.c: In function"main"
: main.c:7:10: error: "c" is used uninitialized in this function [-Werror=uninitialized] cc1: all warnings being treated as errors

15.使用@选项通过文件提供gcc选项

gcc的选项也可以通过文件来提供。这可以使用@选项,后跟包含选项的文件名来完成。不止一个选项由一个空格分隔。

这里是一个例子:

$ cat opt_file  
-Wall -omain  

opt_file包含选项。

现在通过提供opt_file和选项@来编译代码。

$ gcc main.c @opt_file  
main.c: In function ‘main’:  
main.c:6:11: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]  
  
$ ls main  
main  

16.使用Idirname选项将所指出的目录加入到程序头文件目录列表中

通常,我们在编写头文件时用的是#include<studio.h>,这里的<>的意思是表示在系统预设的头文件目录当中搜索相应的文件,对应的,还有#include "filename.h"的写法,这里""的意思是在当前目录下搜索文件,为了在编译文件时,头文件不出错,有事需要将指定的目录加入到程序的头文件目录中,例如:

gcc foo.c -I /home/include -o foo

16.使用Ldirname选项将指出的目录添加到库文件目录列表中

17.使用lname在连接时,装载名称为libname.a的函数库

该函数在系统预设的额目录或自己-L选择的目录下,例如-lm表示连接名为"libm.a"的数学函数库

例子:

gcc foo.c -L /home/lib -lfoo -o foo

18.使用static静态库连接文件

  库有动静两种,动态库用.so为后缀,静态库以.a为后缀,当使用静态库时,连接器找出程序所需的函数,然后将它们拷贝到可执行文件,一旦连接成功,静态程序就不再需要了,然而,对于动态库来说,就不是这样的,静态库会执行程序后留下一个标准,指明当程序执行时,必须载入这个库,由于动态库节省空间,linux下进行连接的缺省操作首先连接动态库。

例:

gcc -static hello.c -o hello

 

19.使用-O1~-O3对程序进行优化编译

利用这个选项,整个编代码都会在编译、链接过程中进行优化,产生的可执行文件效率更高(数值越大优化程度越高),但编译速度会慢一些。

在最后可以在执行时可以用下列代码查看执行时间。

time ./执行文件

20、使用-g加入GDB调试信息。

21、-ggdb尽可能多的加入GDB可以使用的调试信息。

使用GDB之前,必须在程序中加入调试信息,即是用GCC编译时必须使用选项-g,这样GDB才能够调试所使用的变量,代码,函数等。

22、-m更具给定的CPU类型优化代码

23、-M生成于文件关联的信息。

24、产生供gprof使用的信息

25、-v尽可能多的输出信息

26、尽量使用动态连接库。

27、编译C++文件需要用g++

 

posted @ 2018-01-26 13:40  noticeable  阅读(637)  评论(0编辑  收藏  举报