c语言的编译与调试
1. GCC/G++
gcc和g++是GNU Compiler Collection中的编译器,分别用于编译C和C++程序。它们的编译过程主要包括四个步骤:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)、链接(Linking)。
1.1 编译过程
预处理(Pre-Processing):
gcc -E hello.c -o hello.i
对
hello.c文件进行预处理,生成预处理文件hello.i。作用:扩展宏、包含头文件、处理条件编译、删除注释等。
编译(Compiling):
gcc -S hello.i -o hello.s
对预处理文件进行编译,生成汇编文件
hello.s。作用:将高级语言代码转换为汇编语言,便于进一步转换为机器代码。
汇编(Assembling):
gcc -c hello.s -o hello.o
对汇编文件进行汇编,生成目标文件
hello.o。作用:将汇编代码转换为机器代码,包含程序的二进制指令,但还未链接库函数或其他目标文件。
链接(Linking):
gcc hello.o -o hello
对目标文件进行链接,生成可执行文件
hello。作用:生成最终的可执行程序,可以在目标操作系统上运行。
可以一步完成所有过程:
gcc hello.c -o hello
或者只生成目标文件:
gcc -c hello.c -o hello.o
1.2 GCC基本使用
编译单个C文件并生成可执行文件:
gcc -o outputfile sourcefile.c
-o outputfile:指定输出的可执行文件名。sourcefile.c:要编译的源文件。编译多个C文件并生成可执行文件:
gcc -o myprogram file1.c file2.c file3.c
编译并生成目标文件(.o文件):
gcc -c file.c
-c:仅编译,生成目标文件(object file)。指定头文件目录:
gcc -Iinclude -o myprogram src/file1.c src/file2.c
-Iinclude:指定包含头文件的目录include。详细解释:
-I选项用于指定头文件的搜索目录。这在包含自定义头文件或者头文件不在标准目录时非常有用。头文件(
.h或.hpp文件)通常包含函数声明、宏定义、数据类型、预处理指令等。当编写一个程序时,头文件可以被多个源文件包含,以便共享这些声明和定义。编译器默认会在一些标准目录中搜索头文件,比如
/usr/include和/usr/local/include。如果头文件不在这些默认目录中,编译器就无法找到它们,会报错。使用
-I选项可以告诉编译器在指定目录中搜索头文件。假设你的头文件在一个自定义目录中,比如include目录,可以使用以下命令:gcc -Iinclude -o myprogram src/main.c
这样编译器就会在
include目录中找到头文件。以下是一个示例:// include/myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H void myFunction(); #endif // src/main.c
#include "myheader.h"
#include <stdio.h> void myFunction() {
printf("Hello from myFunction!\n");
} int main() {
myFunction();
return 0;
}
编译命令:
gcc -Iinclude -o myprogram src/main.c
链接目标文件生成可执行文件:
gcc -o myprogram file1.o file2.o
1.3 GCC常用选项
编译优化:
-O1、-O2、-O3:不同级别的优化。-Os:优化生成的代码大小。调试信息:
-g:生成调试信息,用于调试程序。警告信息:
-Wall:启用所有常见的警告。-Werror:将所有警告视为错误。
1.4 G++使用
g++用于编译C++程序,使用方法与gcc类似:
编译单个C++文件并生成可执行文件:
g++ -o outputfile sourcefile.cpp
编译多个C++文件并生成可执行文件:
g++ -o myprogram file1.cpp file2.cpp
编译并生成目标文件(.o文件):
g++ -c file.cpp
-c:仅编译,生成目标文件(object file)。指定头文件目录:
g++ -Iinclude -o myprogram src/file1.cpp src/file2.cpp
-Iinclude:指定包含头文件的目录include。链接目标文件生成可执行文件:
g++ -o myprogram file1.o file2.o
2.Makefile
Makefile 是用于自动化编译和构建软件项目的工具。在大型项目中,手动编译每个文件非常繁琐,使用 Makefile 可以简化这一过程。Makefile 由一系列规则(rules)组成,每个规则包含目标(target)、依赖(dependencies)和命令(commands)。
2.1 基本结构
一个基本的 Makefile 的规则结构如下:
target: dependencies
command
- target:要生成的文件或目标,可以是可执行文件、目标文件或其他规则。
- dependencies:生成目标所依赖的文件或其他目标。
- command:生成目标所需执行的命令。
2.2 示例
假设有以下项目结构:
project/
├── include/
│ └── myheader.h
├── src/
│ ├── main.c
│ ├── file1.c
│ ├── file2.c
├── Makefile
Makefile 内容如下:
# 指定编译器
CC = gcc
# 编译选项
CFLAGS = -Wall -g -Iinclude
# 源文件目录
SRC_DIR = src
# 所有的源文件
SRCS = $(wildcard $(SRC_DIR)/*.c)
# 生成的目标文件
OBJS = $(SRCS:.c=.o)
# 生成的可执行文件名
TARGET = myprogram
# 默认规则,生成最终的可执行文件
all: $(TARGET)
# 生成最终的可执行文件 $(TARGET),依赖所有目标文件 $(OBJS)
$(TARGET): $(OBJS)
$(CC) -o $@ $^
# 生成目标文件的规则
$(SRC_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
# 清理规则
clean:
rm -f $(OBJS) $(TARGET)
# 打印文件列表
print:
@echo "Source files: $(SRCS)"
@echo "Object files: $(OBJS)"
# 伪目标
.PHONY: all clean print
2.3 变量
- CC:指定编译器,通常为
gcc或g++。 - CFLAGS:编译选项,如包含目录(
-I)、警告(-Wall)、调试信息(-g)等。 - SRCS:源文件列表,由
wildcard函数生成。 - OBJS:目标文件列表,由源文件列表通过模式替换生成。
- TARGET:最终生成的可执行文件名。
2.4 规则说明
all 规则:
all: $(TARGET)
默认规则,生成目标文件
$(TARGET)。$(TARGET) 规则:
$(TARGET): $(OBJS)
$(CC) -o $@ $^
生成最终的可执行文件
$(TARGET),依赖所有目标文件$(OBJS)。模式规则:
$(SRC_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $@
通用规则,将
.c文件编译为.o文件。$<代表第一个依赖文件(即源文件),$@代表目标文件(即目标文件)。clean 规则:
clean:
rm -f $(OBJS) $(TARGET)
清理规则,删除生成的目标文件和可执行文件。
print 规则:
print:
@echo "Source files: $(SRCS)"
@echo "Object files: $(OBJS)"
打印文件列表,使用
@符号避免输出命令本身。伪目标:
.PHONY: all clean print
声明
all、clean和print为伪目标,以避免与实际文件名发生冲突。伪目标用于告知make这些规则不生成文件,而是特殊的操作。因此,make会忽略它们的时间戳,总是执行这些规则。
2.5 常用命令
make:
make
执行
Makefile中的默认规则(通常为all规则)。make clean:
make clean
执行
clean规则,清理生成的文件。make -f 其他Makefile文件:
make -f other_makefile
使用指定的
Makefile文件进行构建。
3. CMake
CMake 是一个跨平台的构建系统,用于管理软件的编译过程。在大型项目中,手动管理编译配置非常繁琐,使用 CMake 可以简化这一过程。CMake 通过 CMakeLists.txt 文件定义项目的构建规则。
3.1 基本结构
一个基本的 CMakeLists.txt 的结构如下:
- cmake_minimum_required:指定最低版本的
CMake。 - project:定义项目名称。
- set:设置编译选项和变量。
- include_directories:包含目录。
- add_executable:生成可执行文件。
- add_library:生成库文件(可选)。
- target_link_libraries:链接库文件(可选)。
3.2 示例
假设有以下项目结构:
project/
├── include/
│ └── myheader.h
├── src/
│ ├── main.cpp
│ ├── file1.cpp
│ ├── file2.cpp
├── CMakeLists.txt
CMakeLists.txt 内容如下:
# CMake 最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目信息
project(MyProject)
# 指定 C++ 标准
set(CMAKE_CXX_STANDARD 11)
# 包含头文件目录
include_directories(include)
# 查找 src 目录下的所有源文件
file(GLOB SRCS "src/*.cpp")
# 生成可执行文件
add_executable(myprogram ${SRCS})
3.3 变量
- CMAKE_CXX_STANDARD:指定 C++ 标准,如
11、14、17等。 - SRCS:源文件列表,由
file(GLOB)函数生成。
3.4 命令说明
cmake_minimum_required:
cmake_minimum_required(VERSION 3.10)
指定最低版本的
CMake。project:
project(MyProject)
定义项目名称。
set:
set(CMAKE_CXX_STANDARD 11)
设置编译选项,这里指定使用 C++11 标准。
include_directories:
include_directories(include)
包含头文件目录。
file(GLOB):
file(GLOB SRCS "src/*.cpp")
查找并设置源文件列表,
GLOB表示使用通配符匹配文件。add_executable:
add_executable(myprogram ${SRCS})
生成可执行文件
myprogram,并指定源文件列表。
3.5 常用命令
配置项目:
cmake .
在当前目录下生成构建文件。
生成项目:
make
使用生成的构建文件进行编译。
构建目录:
mkdir build
cd build
cmake ..
make
创建一个单独的构建目录,进行 out-of-source 构建,保持源代码目录整洁。
清理项目:
手动删除
build目录或使用make clean命令(需在CMakeLists.txt中添加相应规则)。打印源文件列表:
在调试时,可以添加
message命令以打印源文件列表,确保它们被正确识别:message(STATUS "Source files: ${SRCS}")
4. GDB
GDB(GNU 调试器)是一个强大的调试工具,用于调试 C、C++ 和其他语言编写的程序。它可以在程序运行时设置断点、检查变量值、单步执行代码等,帮助开发者找到并修复错误。
4.1 基本命令
启动 GDB:
gdb program
其中
program是要调试的可执行文件。运行程序:
run
启动程序。如果程序需要参数,可以在
run命令后添加,例如run arg1 arg2。设置断点:
break [file:]function
break [file:]line
在指定函数或行设置断点。例如:
break main
break myfile.c:10
列出断点:
info breakpoints
显示当前设置的断点。
删除断点:
delete [breakpoint-number]
删除指定编号的断点,如果不指定编号则删除所有断点。
单步执行:
step
next
step进入函数内部,next跳过函数调用。继续运行:
continue
继续执行程序,直到遇到下一个断点。
打印变量值:
print variable
打印变量的当前值。例如:
print x
查看调用栈:
backtrace
显示当前的函数调用栈。
查看局部变量:
info locals
显示当前函数的局部变量。
4.2 示例
假设有以下 C 程序 example.c:
#include <stdio.h>
void function1() {
int x = 10;
printf("x = %d\n", x);
}
int main() {
function1();
return 0;
}
编译程序,并启用调试信息:
gcc -g -o example example.c
启动 GDB 并调试程序:
gdb example
在 GDB 中执行以下命令:
运行程序:
run
设置断点:
break function1
继续运行:
continue
单步执行:
step
打印变量值:
print x
查看调用栈:
backtrace
查看局部变量:
info locals
c语言的编译与调试的更多相关文章
- 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析
上次的Hello world算是入门了,现在学习一些相关工具的使用 编译自动化 写好程序,首先要编译,就用gcc就好了,基本用法如下 gcc helloworld.c -o helloworld.o ...
- C语言模块化编译介绍
C语言模块化编译介绍 模块化编程的概念 所谓模块化变成(多文件开发),就是多文件(.c文件)编程,一个.c文件和一个.h文件可以被称为一个模块. 头文件开发的注意事项: 1)头文件中可以和C程序一样引 ...
- 附录三 嵌入式C程序的编译与调试
课程回顾 C语言库的特性和发展 C语言库的常用库函数 标准库函数的特色应用 git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysi ...
- 开发者说 | 使用Visual Studio Code编译、调试Apollo项目
转载地址:https://mp.weixin.qq.com/s?__biz=MzI1NjkxOTMyNQ==&mid=2247484266&idx=1&sn=d6bcd4842 ...
- 如何编译和调试Python内核源码?
目录 写在前面 获取源代码 源代码的组织 windows下编译CPython 调试CPython 小结 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 如果对Pyth ...
- VScode 配置 C++ 环境进行编译和调试
这里记录为 VScode 配置 C++ 环境的简单步骤,实践环境为 Ubuntu 18.04 ,VScode 1.27 .在 Ubuntu 环境下,系统默认安装 gcc 和 g++ 编译器,故而下列步 ...
- C语言简单编译预处理-笔记
预处理指令 所谓预处理,是指,在编译之前对程序源码进行初步的转换,产生新的源代码提供给编译器.预处理时主要完成:包含其他源文件,定义宏,根据条件决定编译时是否包含某些代码(>防止重复包含某些文件 ...
- 剖析并利用Visual Studio Code在Mac上编译、调试c#程序
0x00 前言 一周多以前的微软的Build大会上,微软发布了一个让很多人眼前一亮的工具,也是本文的主角——Visual Studio Code.很多使用Windows的朋友都很高兴,认为又多了一个很 ...
- C语言的编译过程、安装gcc编译器以及设置环境变量
以我对C语言编译过程的了解,我用了一点时间画了一个图,提供给大家参考一下,希望有些能对您的问题提上帮助. 前几天刚初步学习了C语言的编译过程,感触挺深的.在C语言中头文件其实起了一个很大的作用. 1. ...
- Koala – 开源的前端预处理器语言图形编译工具
koala 是一个前端预处理器语言图形编译工具,支持 Less.Sass.Compass.CoffeeScript,帮助 Web 开发者更高效地使用它们进行开发.跨平台运行,完美兼容 Windows. ...
随机推荐
- 使用爬虫利器 Playwright,轻松爬取抖查查数据
使用爬虫利器 Playwright,轻松爬取抖查查数据 我们先分析登录的接口,其中 url 有一些非业务参数:ts.he.sign.secret. 然后根据这些参数作为关键词,定位到相关的 js 代码 ...
- Pandas学习之路【3】
新增列的一些操作 1.新增一个列,直接给列赋值 # 取所有行,新增的列为new_col df.loc[:, 'new_col'] = 100 2.使用df.apply方法给新增的列赋值 def get ...
- 2024盘古石取证比赛(APK)
题目列表 使用软件: Notepad++,火眼证据分析软件,雷电分析app,DB browser for SQLCipher 1. 分析伏季雅的手机检材,手机中诈骗APP的包名是:[答案格式:abc. ...
- .NET桌面程序混合开发之二:在原生WinFrom程序中使用WebView2
本文将介绍如何在WinForms中嵌入WebView2,并讲到WebView2的主要特征.点击了解更多WebView2的API. 1. 准备 Visual Studio 2017 及以上版本 WebV ...
- C# 关于图片转ICO的代码整理(无损,不需要第三方类库)
概述(Overview) 感觉网上文章整理的不全,我这边做个专栏,专门做这个事情吧,节省大家搜索.筛选.整理的时间精力.有用可以点个赞.引用本文章请注明出处,谢谢. (I feel that the ...
- FlexBox 行间距
问题背景 在Flex布局方式下, 父容器约定是换行的方式, 不足以容纳一行子元素的时候, 会单独进行折行, 那么折行的行间距如何处理呢? 解决办法 通过在子Item上面设置margin-top可以模拟 ...
- @synchronized(self) 加锁引起的Crash
一.最近米家App进入前台的时候上报上来一个Crash {"app_name":"MiHome","timestamp":"201 ...
- (JAVA)设计模式-适配器模式
模式的定义和特点: 适配器模式(Adapter)是一种将一个类的接口转换成客户希望的另外一个接口的设计模式,可以提高代码的复用性和灵活性. 结构与实现: 定义一个适配器类来实现业务接口,再继承现有组件 ...
- kettle从入门到精通 第六十四课 ETL之kettle kettle中执行SQL脚本步骤,使用需当心
1.群里有不定时会有同学反馈执行SQL脚本步骤使用有问题,那么咱们今天一起来学习下该步骤.trans中的执行SQL脚本有两方面功能,使用时需小心,不然很容易踩坑. 官方定义: 翻译: 您可以使用此步骤 ...
- P1737
problem \(\text{task 1}\) 要求: 输入:\(a,b\). 输出:\(-2a-2b\). 数据范围:\(|a|,|b| \le 10^9\). 做法: 先把 \(-2\) 提出 ...