GCC简介
- GCC 原名为 GNU C 语言编译器(GNU C Compiler),只能处理 C 语言。但其很快扩展,变得可处理 C++,后来又扩展为能够支持更多编程语言,如 Fortran、Pascal、Objective -C、Java、Ada、Go 以及各类处理器架构上的汇编语言等,所以改名 GNU 编译器套件(GNU Compiler Collection)。
- GCC(特别是其中的 C 语言编译器)也常被认为是跨平台编译器的事实标准。
- GCC 提供了 30 多条警告信息和 3 个警告级别,使用它们有助于增强程序的稳定性和可移植性。
- GCC 还对标准的 C/C++ 语言进行了大量的扩展,提高了程序的执行效率,有助于编译器进行代码优化,能够减轻编程的工作量。
GCC编译过程
GCC编译步骤
- 预处理(Pre-Processing);
- 编译(Compiling),检查语法错误;
- 汇编(Assembling),生成二进制文件,还不能执行;
- 链接(Linking),链接库文件。
GCC常用选项
- -c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
- -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
- -g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。
- -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
- -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
- -I dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。(gcc main.c file.c -I inlcude)
- -L dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。(gcc test.c -o test -lpthread 链接库文件) (gcc test.c -o test -L/home/linux -lpthread 指定某个目录下的库文件 )
#include <stdio.h>
int fun(){
return 1;
}
int a = 5;
int main(int argc, const char *argv[])
{
static int c;
fun();
return 0;
}
gcc -E demo01.c -o demo01.i
demo01.i文件
# 1 "demo01.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "demo01.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 375 "/usr/include/features.h" 3 4
# 1 "/usr/include/sys/cdefs.h" 1 3 4
# 392 "/usr/include/sys/cdefs.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 393 "/usr/include/sys/cdefs.h" 2 3 4
# 376 "/usr/include/features.h" 2 3 4
# 399 "/usr/include/features.h" 3 4
# 1 "/usr/include/gnu/stubs.h" 1 3 4
# 10 "/usr/include/gnu/stubs.h" 3 4
# 1 "/usr/include/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/gnu/stubs.h" 2 3 4
# 400 "/usr/include/features.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 1 3 4
# 212 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 34 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/bits/types.h" 1 3 4
# 27 "/usr/include/bits/types.h" 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4
# 28 "/usr/include/bits/types.h" 2 3 4
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
#........................
# 943 "/usr/include/stdio.h" 3 4
# 2 "demo01.c" 2
int fun(){
return 1;
}
int a = 5;
int main(int argc, const char *argv[])
{
static int c;
fun();
return 0;
}
gcc -S demo01.i -o demo01.s
demo01.s文件
.file "demo01.c"
.text
.globl fun
.type fun, @function
fun:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $1, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size fun, .-fun
.globl a
.data
.align 4
.type a, @object
.size a, 4
a:
.long 5
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $0, %eax
call fun
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.local c.2183
.comm c.2183,4,4
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
.section .note.GNU-stack,"",@progbits
gcc -c demo01.s -o demo01.o
demo01.o文件是二进制文件
gcc demo01.o -o demo01
demo01文件:有权限可执行文件
条件编译
一般情况下,C语言源程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译(conditional compile)。
#include <stdio.h>
int main(int argc, const char *argv[])
{
#ifdef A
#define N 10
printf("%d\r\n",N);
#endif
#ifdef B
#define M 20
printf("%d\r\n",M);
#endif
#if VALUE
printf("=============\r\n");
#else
printf("*************\r\n");
#endif
return 0;
}
使用-D编译:gcc demo01.c -D A -D VALUE=1
来选择需要编译那部分的代码块。
在创建h文件时可以做到去重复定义:
database.h
#ifndef _DATABASE_H
#define _DATABASE_H
//.....
#endif
//这里要隔一行