23

15个最常用的GCC编译器参数

 2年前 阅读数 27
以下为 快照 页面,建议前往来源网站查看,会有更好的阅读体验。
原文链接: https://colobu.com/2018/08/28/15-Most-Frequently-Used-GCC-Compiler-Command-Line-Options/?amp%3Butm_medium=referral

原文: 15 Most Frequently Used GCC Compiler Command Line Options 以及评论中大家提供的一些参数。

GCC编译器是一个日常流行的 C 编译器, 很多Linux的发布版本中都带有这个编译器。这篇文章列举了一些最常用的编译参数。

本文中使用下面的C语言实现的例子:

#include<stdio.h>

int main(void)
{
   printf("\n The Geek Stuff\n");
   return 0;
}

指定编译输出的名字

gcc编译器最常用的使用格式是:

gcc main.c

上面的命令执行完整的编译过程,并且生成一个 a.out 文件。

使用参数 -o , 可以指定输出的文件名。

gcc main.c -o main

上面的命令会产生输出文件 main

为了理解GCC编译器的完整的编译过程,可以阅读 Journey of a C Program to Linux Executable in 4 Stages

通过 -Wall 参数启用所有警告

这个参数可以启用所有警告。

#include<stdio.h>

int main(void)
{
   int i;
   printf("\n The Geek Stuff [%d]\n", i);
   return 0;
}

上面的代码编译时,会出现 未初始化的i 类似的警告。

$ gcc -Wall main.c -o main
main.c: In function ‘main’:
main.c:6:10: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]

使用 -E 参数只产生预处理输出

-E 参数是产生预处理阶段的输出。

$ gcc -E main.c > main.i

gcc命令将结果输出在 stdout 中,所以你可以把它重定向到任意的文件中,在上面的例子中,重定向到 main.i 文件中。

使用 -S 参数只产生汇编代码

-S 参数产生汇编级别的代码。

gcc -S main.c > main.s

文件 main.s 包含汇编代码。

使用 -C 参数只产生编译的代码

-C 参数只产生编译的代码(没有链接link)。

gcc -C main.c

上面的代码产生 main.o , 包含机器级别的代码或者编译的代码。

使用 -save-temps 参数产生所有的中间步骤的文件

-save-temps 可以做4,5,6步骤的工作。通过这个参数,所有中间阶段的文件都会存储在当前文件夹中,注意它也会产生可执行文件。

$ gcc -save-temps main.c

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

从例子中我们可以看到各个中间文件以及可执行文件。

使用 -l 参数链接共享库

-l 可以用作链接共享库,例如:

gcc  -Wall main.c -o main -lCPPfile

上面的代码会链接 libCPPfile.so ,产生可执行文件 main

使用 -fPIC 产生位置无关的代码

当产生共享库的时候,应该创建位置无关的代码,这会让共享库使用任意的地址而不是固定的地址,要实现这个功能,需要使用 -fPIC 参数。

下面的例子产生 libCfile.so 动态库。

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

产生共享库的时候使用了 -fPIC 参数。

注意 -shared 产生共享库。

使用 -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)
...
...
...

这样我们可以看到所有的细节。

使用 -ansi 参数支持 ISO C89程序

使用 -ansi 参数可以支持 ISO C89风格。

比如下面的代码:

#include<stdio.h>

int main(void)
{
  // Print the string
   printf("\n The Geek Stuff\n");
   return 0;
}

使用 -ansi 参数编译上面的代码会出错,因为ISO C89不支持C++风格的注释。

下面是输出结果:

main.c: In function ‘main’:
main.c:5:3: error: expected expression before ‘/’ token

我们可以看待上面编译的时候抛出一个注释错误。

使用 -funsigned-char 将char解释为符号的char

通过这个参数, char类型被看作为 unsigned char类型。

例子:

#include<stdio.h>

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

上面的代码通过这个参数编译后,输出结果为:

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

 The Geek Stuff [246]

可以看到char是无符号的字节。

使用 -fsigned-char 将char解释为有符号的char

和上面的功能相反, 使用这个参数, char类型被看作是有符号的:

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

 The Geek Stuff [-10]

结果输出为负数。

使用 -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]

可以看到宏被定义了,并打印出了结果。

tput confirms that the macro was defined.

使用 -Werror 将警告升级为错误

通过这个参数,gcc会将所有的警告转换成错误信息。

例子:

#include<stdio.h>

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

上面的代码编译的时候会有一个 undefined variable 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

使用 @ 参数从文件中读取参数

gcc参数可以从文件中读取,通过 @ 后跟文件名的方式提供, 多个参数可以使用空格区隔。

例子:

$ cat opt_file 
-Wall -omain

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

输出结果表明参数的确从文件中读取了,并且正确的应用到编译过程中。

以下是附加的一些编译参数

使用参数 -I 指定头文件的文件夹

gcc -I/home/codeman/include input-file.c

-I- 取消前一个参数功能,一般用在 -Idir 之后。

使用参数 -std 指定支持的c++/c的标准

gcc -std=c++11 hello-world.cpp

标准如 c++11, c++14, c90, c89 等。

使用 -static 生成静态链接的文件

静态编译文件(把动态库的函数和其它依赖都编译进最终文件)

gcc main.c -static -o main -lpthread

相反的使用 -shared 使用动态库链接。

使用 -static-libstdc++ 静态链接libstdc++

如果没有使用 -static ,默认使用libstdc++共享库,而 -static-libstdc++ 可以指定使用libstdc++静态库。

使用 -M 生成文件关联的信息

gcc -M main.c
main.o: main.c /usr/include/stdc-predef.h /usr/include/stdio.h \
 /usr/include/features.h /usr/include/sys/cdefs.h \
 /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \
 /usr/include/gnu/stubs-64.h \
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h \
 /usr/include/bits/types.h /usr/include/bits/typesizes.h \
 /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stdarg.h \
 /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h

全部参数介绍

https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html


猜你喜欢

  • 22
    • www.shichangbu.com 2年前
    • 快照

    请查收,15个消费心理学理论

    微信号: 非主流朱(ID:feizhuliupig) 如何推广产品,提...

  • 39

    Tutorialzine每月都会给我们精心挑选优秀的web开发资源,这些资源可以帮助我们解锁最新和最炫酷的网络开发姿势。前端er,让我们一起先睹为快吧! Polly.js polly是一个用于记录,重放和模拟HTTP交互的开源库。它提供了一套完善且易用的AP

  • 51

    默认情况下,安装的Linux发行版中包含一些别名。Linux命令行别名非常有助于提高工作效率。默认情况下会在安装的Linux发行版中包含一些内容。

  • 29
    • 掘金 juejin.im 1年前
    • 快照

    HTTP 的15个常见知识点复习

    前言 自从入职新公司到现在,我们前端团队内部一直在做 ?每周一练 的知识复习计划,我之前整理了一个 每周一练 之 数据结构与算法 学习内容,大家也快去看看~~ 最近三周,主要复习 网络基础 相关的知识,今天我把这三周复习的知识和参考答案,整理成本文,欢迎各位...

  • 15
    • 掘金 juejin.im 1年前
    • 快照

    15个 Vue.js 高级面试题

    2019年12月02日阅读 2438915个 Vue.js 高级面试题 翻译:疯狂的技术宅 www.zeolearn.com/intervi...

  • 27

    作者:zaiste 翻译:疯狂的技术宅 原文:zaiste.net/15-git-comm… 未经允许严禁转载 Git 有时可能会令人生畏。因为有太多的命令和细节需要学习。不过虽然文档的内容很多,但阅读起来还是很轻松的。一旦你克服了最初不堪重负的感觉,就会感

  • 13
    • 微信 mp.weixin.qq.com 1年前
    • 快照

    15个基本的C#面试问题

    原文来自互联网,由长沙DotNET技术社区【笑语】编译。 原文来自:https://www.toptal.com/c-sharp/top-10-mistakes-that-c-sharp-prog...

  • 31

    自从70年代Unix系统诞生以来,它就一直吸引着全世界的目光。帮助Linux和BSD发行版确保其当前地位的基本特性之一是Linux shell。由于其强大的功能和多样的应用程序,shell是许多Linux爱好者的必备工具之一。它是操作系统的命令行接口,允许...

  • 7

    自2004年以来,我每天都在使用macOS,自从OSX Panther(2003年10月发布)以来,我使用过该操作系统的每一个版本,而且自从Lion 10.7(2011年...

  • 6

    (接上文) 隐藏桌面上的所有文件 技巧 chflags hidd...

关于极客头条


聚合每日国内外有价值,有趣的链接。