GCC简介
GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器。它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分。GCC原本作为GNU操作系统的官方编译器,现已被大多数类Unix操作系统(如Linux、BSD、Mac OS X等)采纳为标准的编译器,GCC同样适用于微软的Windows。 GCC是自由软件过程发展中的著名例子,由自由软件基金会以GPL协议发布。
GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理 C语言。GCC 很快地扩展,变得可处理 C++。后来又扩展能够支持更多编程语言,如Fortran、Pascal、Objective-C、Java、Ada、Go以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件(GNU Compiler Collection)
GCC 编译器在编译一个C语言程序时,过程可以细分为四个阶段:
gcc -E
: 将C语言源程序预处理
,生成.i文件。
gcc -S
:预处理后的.i文件编译
成为汇编语言,生成.s文件。
gcc -c
:将汇编语言文件经过汇编
,生成目标文件.o文件。
gcc -o 文件名
:将各个模块的.o文件链接
起来生成一个可执行程序文件。-o的作用是指定生成文件的文件名
程序员可以对编译过程进行控制,同时GCC提供了强大的代码优化功能。
gcc -v
查看gcc版本
c程序中的文件后缀名
扩展名 | 说明 |
---|---|
.h | 头文件 |
.c | C源文件 |
i | 预处理后的c源文件 |
.s | 汇编程序文件 |
.o | 目标文件 |
.a | 静态链接库 |
.so | 动态链接库 |
gcc 其他常用参数:
参数 | 功能 |
---|---|
-o | 指定输出文件:: gcc a.c -oa.exe(默认为a.out) |
-Wall | 生成尽可能多的警告信息 |
-Werror | 要求编译器将警告当做错误处理 |
-x | 指定编译代码类型:-x none根据后缀自动识别 |
-g | 生成调试信息 |
-O | 优化:等级分为O0(不优化)、O1(默认)、O2、O3 |
-w | 不生成任何警告信息。 |
-static | 禁止使用共享连接。 |
预处理指令介绍
预编译指示符号 | 说明 |
---|---|
#define | 定义宏或者宏函数 |
#if、#ifdef、#ifndef、#elif、#else | 条件编译 |
#endif | 结束条件编译 |
#include | 将指定的文件插入当前位置 |
#include_next | 与include一样,但从当前目录之后的目录查找 |
#line | 指定行号 |
#pragma | 提供额外信息的标准方法,可用来指定平台 |
#undef | 删除宏 |
#waring | 创建一个警告 |
#error | 产生错误,挂起预处理程序 |
## | 连接操作符号,用于宏内连接两个字符串 |
示例:
错误和警告
#define VERSION 3
#if (VERSION < 2)
#error "版本过低"
#else
#waring "版本高"
#endif
头文件
系统头文件使用:#Include <…> 在系统指定的目录以及I参数目录查找
用户头文件使用:#include “…” 先在当前路径查找后再去系统指定的目录及I参数指定的目录查找。
#pragma
#pragma 有一个等价的宏_Pragma
#pragma GCC poison int
等于 _Pragma("GCC poison int")
#pargma GCC dependency "文件名a "
:指定文件a比当前文件新的时候会产生提示警告。
#pargma GCC posion 标识符
: 标识符将被定义为毒药,禁止继续使用,否则产生错误。
pragma pack(1)
: 可以指定结构的对齐和补齐的字节数。
预定义宏介绍
宏 | 说明 |
---|---|
__BASE_FILE | 源代码的完整路径 |
__DATE__ | 日期 |
__FILE__ | 源代码文件名 |
__FUNCTION__ | 当前函数名,同(__func__ ) |
__INCLUDE_LEVEL__ | 包含的层数,基本为0 |
__LINE__ | 行数 |
__TIME__ | 时间 |
宏__cplusplus主要解决C/C++混合编程问题,一般用法如下:
#ifdef __cplusplus
extern "C" {
#endif
… //被extern “C”修饰的变量和函数按照C语言方式编译和链接。
#ifdef __cplusplus
}
#endif
修改环境变量
Linux终端中执行export PATH=$PATH:.
: 当前窗口有效。
cd ~
后.bashrc
文件末尾加上export PATH=$PATH:.
执行 . .bashrc
。
编译环境变量
C_INCLUDE_PATH
: 查找头文件的目录。c。
CPLUS_INCLUDE_PATH
: 查找头文件的目录。C++。
CPATH
: 查找头文件,相当于-I选项。与上面重合。
LIBRARY_PATH
: 编译时,查找库文件(静态库和共享库),-l选项。
LD_LIBRARY_PATH
:运行时定位共享库
程序员自定义头文件的几种查找方法:
- 用
" "
中放入路径的方式:"./test/xx.h"
- 把目录配置到环境变量CPATH中。
- 用
gcc -I 头文件目录
进行编译连接。
静态库的创建和使用
-
编译静态库
gcc -c -static test.c
:-static
为可选项,阻止gcc使用共享库。不使用共享库减少运行时间开销,但文件会变大。ar -r libtest.a
test.oar
指令 语法:ar [选项] 归档文件名 目标文件列表
项 说明 -d 从归档文件删除制定目标文件列表 -q 将指定目标文件快速附加到归档文件末尾。 -r 将指定目标文件插入文档,如存在则更新。 -t 显示目标文件列表 -x 把归档文件展开为目标文件 -
使用静态库
gcc main.c libtest.a
gcc main.c -ltest
(libtest.a必须在LIBRARY_PATH的指定目录中)gcc main.c -ltest -L(库目录)
共享库的创建和使用
- 编译共享库
gcc -c -fpic test.c
gcc -shard test.o -o libtest.so
-fpic不写也可以gcc -fpic -shard test.c -o libtest.s
- 使用共享库与静态库方式一样
gcc main.c libtest.so
gcc main.c -ltest
(libtest.so必须在LIBRARY_PATH的指定目录中)gcc main.c -ltest -L(库目录)
编译时依赖LIBRARY_PATH,但共享库运行时依赖LD_LIBRARY_PATH。
ldd
命令可以查看应用程序所使用的共享库
系统提供了一套API可以直接打开共享库:
#include <dlfcn.h>
void * dlopen(const char *filename, int flag);
:打开库文件。flag:RTLD_LAZY(符号查找时候才加载),RTLD_NOW(立刻加载)。
void *dlsym(void *handle, const char *symbol);
: 从打开的库文件中得到函数
int dlclose(void *handle);
: 关闭
char *dlerror(void);
: 判断是否出错