最近在看操作系统,有些地方总需要写写代码尝试一下。但好多东西都不是在 windows 下尝试的,没办法必须使用 Linux 环境下的 C++。总归 GCC/gdb 的相关基础是要提上日程的,这里通过网上看的东西,稍微整理一些入门,增加一些入门知识,也备不时之需。
GCC相关内容
什么是gcc和g++
- GCC 是指 GNU Compiler Collection,是一种支持多种语言的编译器。GNU 编译套件包括包括 C/C++, Objective-C, Fortran, Java, Ada 和 Go 语言等。
- 对 C 语言 gcc 调用 C compiler,对 C++则 g++调用 C++ compiler。
- 两者区别:
.cpp
和.c
对于 gcc 时不一样的,对 g++都作为.cpp
文件编译- g++会自动链接标准库 STL,gcc 不会。
- gcc 编译
.c
时预定义宏比较少。gcc 编译.cpp
和 g++编译.c
和.cpp
时都会添加额外的宏。 - gcc 编译 c++为了使用 STL,可添加参数-lstdc++。但两者并不只是这个差距。
下面是其他编译器或解释器名称。C(gcc), C++(g++), Java(编译器:gcj, 解释器:gij), Objective-C(gobjc)
gcc的特点
- 可移植性,支持多种平台常见的 ARM,X86 等。
- gcc 可实现本地编译和跨平台交叉编译。
- 支持语言多。
- gcc 模块化设计,可以添加新的语言和新的 CPU 架构支持。
- gcc 自由软件。GNU。
gcc编译过程
- 主要分为四个步骤:预处理 Pre-Processing,编译 Compiling,汇编 Assembling,链接 Linking,过程如下图。
- 预处理:将头文件、宏等进行展开,去除注释等。不会有语法检查。代码会大量扩充。
- 编译:根据不同语言编译器,进行编译,生成汇编代码。会检查语法。
- 汇编:生成目标代码。
- 链接:将程序需要的目标文件进行链接生成可执行文件。

gcc常用选项
选项名称 | 作用 |
---|---|
-o | 产生目标(.i , .s , .o 可执行文件等) |
-O/-O2 | 优化编译、链接,执行效率会高,编译会慢 |
-E | 运行 C 预编译器, 产生.i |
-S | 产生汇编文件后停止,.s |
-c | 取消链接步骤,仅编译源码,并在最后生成目标文件 |
-Wall | 让 gcc 对源码有问题的地方发出警告 |
-I [dir] | 将 dir 目录加入到头文件搜索目录路径中 |
-L [dir] | 将 dir 目录加入到库的搜索目录路径中 |
-lib | 链接 lib 库 |
-g | 在目标文件中嵌入调试信息,例如 gdb 之类的 |
-v | gcc 在执行过程中的详细过程,gcc 及相关程序版本号 |
使用的代码示例
gcc -E hello.c -o hello.i 对hello.c文件进行预处理,生成了hello.i 文件
gcc -S hello.i -o hello.s 对预处理文件进行编译,生成了汇编文件
gcc -c hello.s -o hello.o 对汇编文件进行编译,生成目标文件,不链接不包含子程序文件
gcc hello.o -o hello 对目标文件进行链接,生成可执行文件,不给名字则为x.out
gcc hello.c -o hello 直接编译链接成可执行目标文件
gcc -c hello.c 或 gcc -c hello.c -o hello.o 编译生成可重定位目标文件
gcc -Wall bad.c -o bad 提示编译器报出警告错误
多文件联合编译和分别独立编译
g++ linkHello.c test.c -o main 多个文件联合编译, 可以不添加.h库文件, 但是相应的.c文件要编译
分别独立编译,使得未修改文件无需再编译
g++ -c linkHello.c -o linkHello.o 编译linkHello.c生成不链接的目标文件.o
g++ -c test.c -o main.o 编译test.c生成不链接的目标文件.o
g++ linkHello.o mian.o -o main 链接的两个目标文件生成可执行文件
外部库的调用
- 静态库
.a
:链接时将库的代码链接到可执行文件中,运行时每个程序包含一份,不在需要静态库。 - 动态库
.so
或.sa
:运行时才去链接到共享库代码,多个程序共享使用,减小程序体积。 - 一般的库文件所在位置:/usr/include 及其期目录下的 include, /usr/local/include, /usr/lib, /usr/local/lib, /lib。
生成静态库和共享库(动态库)
- 静态库:先生成目标文件
.o
,再打包ar rcs hellolib.a hello.o
,将其打包为hellolib.a
。ar 是 GUN 归档工具,rcs 表示 replace and create(会替换已存在的libhello.a
文件)。 - 静态库使用方法:编译时把它加入进去就行
gcc hellolib.a test.c -o hello
- 动态库生成方法:也需要先生成目标文件
.o
,gcc -shared -fPIC hello.o -o libhello.so
。-shared 表示生成共享库格式, fPIC 表示产生位置无关码,表示与加载的内存地址无关。 - 动态库使用:方法 1. 将动态库放到/usr/lib 目录。方法 2. ~/.bash_profile 中配置 LD_LIBRARY_PATH 变量。方法 3. 配置/etc/ld.so.conf,配置后调用 ldconfig 更新 ld.so.cache。
库搜索路径
- 搜索先后原则:从左到右搜索-l 指定的目录->环境变量指定的目录(头文件 C_INCLUDE_PATH, 库 LIBRARY_PATH)->系统指定的目录。
GDB相关内容
GDB及其功能
- Unix 及类 Unix 下的调试工具。
- 主要包括四方面的功能:
- 启动程序,按照自定义要求启动程序。
- 设置断点。
- 检查程序停止时发生的情况。
- 改变程序。
GDB使用
GDB运行
- 在编译过程中和运行过程中有设置。
g++ -g -std=c++11 linkHello.c test.c -o main.out -g嵌入调试信息 -std=执行标准 gdb main.out 调试
常用的命令
运行指令
run
简写r
:运行程序,如设置断点则停止运行等待下一步命令。continue
简写c
:继续执行,直到下一个断点。next
简写n
:单步执行,不进入函数体内部直接调用。step
简写s
:单步执行,进入函数体内部。until
简写u
:运行到循环体退出循环。循环体有断点,断点仍然会停。until+行号
:运行到某一行,可以跳出循环。finish
:运行程序直到当前函数返回,并打印函数返回时的堆栈地址和返回值以及参数值等信息。call 函数(参数)
:调用程序中可见的函数,并传递“参数”。quit
简写q
:退出 gdb
设置断点
break n
简写b n
:在第 n 行处设置断点(可在行号前设置代码路径和代码名称)b fn1 if a>b
:条件断点设置break func
:在函数 func()的入口处设置断点,如:break cb_buttondelete n
:删除第 n 个断点disable n
:暂停第 n 个断点,可以在启动enable
。enable n
:开启第 n 个断点clear n
:清除第 n 行的断点info breakpoints
简写info b
:显示当前程序的断点设置情况delete breakpoints
:清除所有断点
查看源代码
list 行号
简写l
:列出程序源代码,默认前后共十行。list 函数名
:显示函数名所在的源代码list
:不带阐述,运行时显示当前所在行(程序断点位置,上次 list 后的位置)的前后共十行。运行前则显示程序开始位置之后的 10 行。
打印
print 表达式
简写p
:可以答应被测试程序的有效表达式。包括数字,变量甚至调用函数。display 表达式
:display 命令设置表达式后,每次单步执行指令后,紧接着输出被设置的表达式。watch 表达式
:设置监视点,一旦被监视的“表达式”改变,gdb 强行终止被调试程序。whatis
:查询变量或函数info function
:查询函数扩展 info locals
:显示当前堆栈页的所有变量
查询运行信息
where/bt
:当前运行的堆栈列表;bt backtrace
:显示当前调用堆栈up/down
:改变堆栈显示的深度set args
:参数:指定运行时的参数show args
:查看设置好的参数info program
:来查看程序的是否在运行,进程号,被暂停的原因。
参考链接: