此為牛客網Linux C++課程1.2&1.3的課程筆記。
0. 簡介
1. gcc和g++的安裝
sudo apt install gcc g++
2. gcc常用參數選項
3. gcc工作流程
首先是預處理器對源代碼進行預處理(后綴名.i),主要做以下事情:
- 把頭文件加入到源代碼當中
- 刪除源代碼中的注釋
- 宏替換(如define)
然后通過編譯器編譯成匯編代碼(后綴名.s);
再通過匯編器匯編成目標代碼(后綴名.o);
最后還要與啟動代碼、庫代碼、其他目標代碼進行鏈接,最后生成可執行文件(windows為.exe,linux為.out)。
4. 代碼示例
如下是名為test.c的hello world程序:
#include <stdio.h>#define PI 3.14int main() {// 測試代碼int sum = PI + 10;printf("hello world");return 0;
}
可以執行
gcc test.c
這樣什么參數都不加,可以直接生成a.out可執行文件,然后執行
./a.out
即輸出hello world。
這一過程我們可以分步實現:
執行
gcc test.c -E -o test.i
-E 參數表示只預處理,不編譯;
-o 參數表示生成test.i文件。
生成的test.i文件內容如下(中間部分省略):
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 27 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 1 3 4
# 33 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 424 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 1 3 4
# 427 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 428 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/long-double.h" 1 3 4
# 429 "/usr/include/x86_64-linux-gnu/sys/cdefs.h" 2 3 4
# 425 "/usr/include/features.h" 2 3 4
# 448 "/usr/include/features.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 1 3 4
# 10 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/gnu/stubs-64.h" 1 3 4
# 11 "/usr/include/x86_64-linux-gnu/gnu/stubs.h" 2 3 4
# 449 "/usr/include/features.h" 2 3 4
# 34 "/usr/include/x86_64-linux-gnu/bits/libc-header-start.h" 2 3 4
# 28 "/usr/include/stdio.h" 2 3 4# 1 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 1 3 4
# 216 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 3 4# 216 "/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h" 3 4
typedef long unsigned int size_t;
# 34 "/usr/include/stdio.h" 2 3 4# 1 "/usr/include/x86_64-linux-gnu/bits/types.h" 1 3 4
# 27 "/usr/include/x86_64-linux-gnu/bits/types.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/wordsize.h" 1 3 4
# 28 "/usr/include/x86_64-linux-gnu/bits/types.h" 2 3 4typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;.
.
.
.
.
.extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
# 840 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 868 "/usr/include/stdio.h" 3 4# 2 "test.c" 2# 5 "test.c"
int main() {int sum = 3.14 + 10;printf("hello world");return 0;
}
可見發生了頭文件的替換,宏替換(PI在這里變成了3.14),以及清除了注釋。
然后對test.i進行編譯,執行:
gcc test.i -S -o test.s
-S參數表示編譯但不匯編。
生成test.s匯編文件,內容如下:
.file "test.c".text.section .rodata
.LC0:.string "hello world".text.globl main.type main, @function
main:
.LFB0:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $16, %rspmovl $13, -4(%rbp)leaq .LC0(%rip), %rdimovl $0, %eaxcall printf@PLTmovl $0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE0:.size main, .-main.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0".section .note.GNU-stack,"",@progbits
可見編譯了匯編代碼。
最后對test.s進行匯編,生成目標代碼,執行:
gcc test.s -c -o test.o
-c參數表示編譯、匯編指定文件,但是不進行鏈接。
生成了test.o的二進制文件。
5. gcc和g++的區別