1. GCC/G++

gccg++是GNU Compiler Collection中的编译器,分别用于编译C和C++程序。它们的编译过程主要包括四个步骤:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)、链接(Linking)。

1.1 编译过程

  1. 预处理(Pre-Processing)

    gcc -E hello.c -o hello.i

    hello.c文件进行预处理,生成预处理文件hello.i

    作用:扩展宏、包含头文件、处理条件编译、删除注释等。

  2. 编译(Compiling)

    gcc -S hello.i -o hello.s

    对预处理文件进行编译,生成汇编文件hello.s

    作用:将高级语言代码转换为汇编语言,便于进一步转换为机器代码。

  3. 汇编(Assembling)

    gcc -c hello.s -o hello.o

    对汇编文件进行汇编,生成目标文件hello.o

    作用:将汇编代码转换为机器代码,包含程序的二进制指令,但还未链接库函数或其他目标文件。

  4. 链接(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:指定编译器,通常为 gccg++
  • 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

    声明 allcleanprint 为伪目标,以避免与实际文件名发生冲突。伪目标用于告知 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++ 标准,如 111417 等。
  • 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 中执行以下命令:

  1. 运行程序

    run
  2. 设置断点

    break function1
  3. 继续运行

    continue
  4. 单步执行

    step
  5. 打印变量值

    print x
  6. 查看调用栈

    backtrace
  7. 查看局部变量

    info locals

c语言的编译与调试的更多相关文章

  1. 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析

    上次的Hello world算是入门了,现在学习一些相关工具的使用 编译自动化 写好程序,首先要编译,就用gcc就好了,基本用法如下 gcc helloworld.c -o helloworld.o ...

  2. C语言模块化编译介绍

    C语言模块化编译介绍 模块化编程的概念 所谓模块化变成(多文件开发),就是多文件(.c文件)编程,一个.c文件和一个.h文件可以被称为一个模块. 头文件开发的注意事项: 1)头文件中可以和C程序一样引 ...

  3. 附录三 嵌入式C程序的编译与调试

    课程回顾 C语言库的特性和发展 C语言库的常用库函数 标准库函数的特色应用 git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysi ...

  4. 开发者说 | 使用Visual Studio Code编译、调试Apollo项目

    转载地址:https://mp.weixin.qq.com/s?__biz=MzI1NjkxOTMyNQ==&mid=2247484266&idx=1&sn=d6bcd4842 ...

  5. 如何编译和调试Python内核源码?

    目录 写在前面 获取源代码 源代码的组织 windows下编译CPython 调试CPython 小结 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 如果对Pyth ...

  6. VScode 配置 C++ 环境进行编译和调试

    这里记录为 VScode 配置 C++ 环境的简单步骤,实践环境为 Ubuntu 18.04 ,VScode 1.27 .在 Ubuntu 环境下,系统默认安装 gcc 和 g++ 编译器,故而下列步 ...

  7. C语言简单编译预处理-笔记

    预处理指令 所谓预处理,是指,在编译之前对程序源码进行初步的转换,产生新的源代码提供给编译器.预处理时主要完成:包含其他源文件,定义宏,根据条件决定编译时是否包含某些代码(>防止重复包含某些文件 ...

  8. 剖析并利用Visual Studio Code在Mac上编译、调试c#程序

    0x00 前言 一周多以前的微软的Build大会上,微软发布了一个让很多人眼前一亮的工具,也是本文的主角——Visual Studio Code.很多使用Windows的朋友都很高兴,认为又多了一个很 ...

  9. C语言的编译过程、安装gcc编译器以及设置环境变量

    以我对C语言编译过程的了解,我用了一点时间画了一个图,提供给大家参考一下,希望有些能对您的问题提上帮助. 前几天刚初步学习了C语言的编译过程,感触挺深的.在C语言中头文件其实起了一个很大的作用. 1. ...

  10. Koala – 开源的前端预处理器语言图形编译工具

    koala 是一个前端预处理器语言图形编译工具,支持 Less.Sass.Compass.CoffeeScript,帮助 Web 开发者更高效地使用它们进行开发.跨平台运行,完美兼容 Windows. ...

随机推荐

  1. LOTO示波器软件新增导览功能

    新版本的大部分型号LOTO示波器的上位机软件我们改成了导航工具条方式.原来的方式是把所有功能都显示在不同的标签页中,这样的优点是非常快捷方便,基本上用鼠标一两次点击就能直达想要的功能设置.但是缺点是不 ...

  2. 分享下最近基于Avalonia UI和MAUI写跨平台时间管理工具的体验

    起因 几个月前,我在寻找一款时间管理软件,类似番茄时钟的工具,但是希望可以自定义时间. 需要自定义的场景 做雅思阅读,3篇文件需要严格控制时间分配,需要一个灵活的计时器 定期提醒,每30分钟需要喝水或 ...

  3. 分布式定理--CAP定理

    cap定理指的是,在一个分布式系统中,只能满足cap中的两项. C consistency 一致性 A availability 可用性 P partition tolerance 分区可容错性 -- ...

  4. golang interface 和 struct 添加方法的区别

    在 Go 语言中,struct 和 interface 都可以关联方法,但它们的方式不同: 1. struct 添加方法: 结构体(struct)本身不直接包含方法,但可以通过定义一个指向该结构体类型 ...

  5. LeetCode 683. K Empty Slots K 个空花盆 / LintCode 861. K个空的位置 (C++/Java)

    题目: 一个花园有N个位置.每个位置上有一朵花.这N朵花会在N天内逐一盛开.每天都一定会有并且只有一朵花盛开,从这天起,这朵花将一直处于盛开的状态. 给定一个由数字1到N组成的数组flowers.数组 ...

  6. ETL工具-nifi干货系列 第六讲 处理器JoltTransformJSON

    1.处理器作用 使用Jolt转换JSON数据为其他结构的JSON,成功的路由到'success',失败的'failure'.处理JSON的实用程序不是基于流的,因此大型JSON文档转换可能会消耗大量内 ...

  7. FPS 是啥

    什么是 FPS 呢 ,FPS就是你所编写的应用程序一秒钟运行的次数,一秒钟运行120次,你的 FPS 就是 一百二 什么是帧速率 为什么有帧速率这一说 帧速率在 数学微积分中是平均运行的力度或者说是强 ...

  8. 荣耀无5G开关,荣耀手机,荣耀80GT

    荣耀无5G开关,荣耀手机,荣耀80GT. Magic OS 版本号是:7.0.0.138(C00E135R2P6). 解决方法: 1.进入设置-关于手机-连续点击7次版本号. 会提示,开发者选项已开启 ...

  9. 神奇的JavaScript弱等价类型转换

    JavaScript语言特性 - 类型转换 JavaScript这门语言的类型系统从来没有它表面看起来的那样和善,虽然比起Java.C#等一众强类型语言,它的弱类型使用起来似乎是如此便利,但正因为它极 ...

  10. Freertos学习:08-信号量

    --- title: rtos-freertos-08-ipc-semaphore date: 2020-06-23 11:01:12 categories: tags: - freertos - i ...