C/C++ Linux 开发教程(GCC + CMake) / 01 — C 语言简介与 GCC 环境搭建
C 语言简介与 GCC 环境搭建
1. C 语言历史
C 语言诞生于 1972 年,由 Dennis Ritchie 在贝尔实验室开发,最初用于重写 UNIX 操作系统内核。经过数十年发展,C 语言已成为世界上最重要的编程语言之一。
| 标准 | 年份 | 说明 |
|---|---|---|
| K&R C | 1978 | 《The C Programming Language》定义的非正式标准 |
| ANSI C (C89) | 1989 | 第一个正式标准,也称 C89 / C90 |
| C99 | 1999 | 引入 // 注释、变长数组、stdint.h 等 |
| C11 | 2011 | 多线程支持 _Thread_local、泛型选择 _Generic |
| C17 | 2017 | Bug 修复版本,无新增特性 |
| C23 | 2023 | 最新标准,引入 nullptr、constexpr、属性语法等 |
💡 提示: GCC 默认使用的标准版本取决于 GCC 版本。建议显式指定
-std=选项以确保可移植性。
2. C 语言特点
C 语言之所以经久不衰,源于以下核心特点:
- 底层控制: 可直接操作内存(指针)、访问硬件地址
- 执行效率: 编译后生成原生机器码,性能接近汇编
- 可移植性: 一次编写,到处编译——从嵌入式单片机到超级计算机
- 简洁语法: 关键字仅 32 个(C89),语法精炼
- 生态丰富: 操作系统、数据库、编译器等基础设施几乎全部用 C 编写
⚠️ 注意: C 语言没有垃圾回收、没有内置的边界检查、没有面向对象支持。它赋予程序员极大的自由,也要求程序员对内存管理负责。
3. 安装 GCC
3.1 Linux
# Debian / Ubuntu
sudo apt update
sudo apt install build-essential
# Fedora
sudo dnf install gcc gcc-c++ make
# Arch Linux
sudo pacman -S base-devel
3.2 macOS
# 安装 Xcode Command Line Tools
xcode-select --install
# 或通过 Homebrew 安装 GCC
brew install gcc
3.3 Windows
推荐使用 MSYS2:
# 安装 MSYS2 后,在 MSYS2 终端执行
pacman -S mingw-w64-ucrt-x86_64-gcc
安装完成后,将 C:\msys64\ucrt64\bin 添加到系统 PATH。
3.4 验证安装
gcc --version
输出示例:
gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
Copyright (C) 2023 Free Software Foundation, Inc.
4. 第一个 C 程序
创建文件 hello.c:
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}
编译并运行:
gcc -o hello hello.c
./hello
输出:
Hello, World!
代码解析
| 行 | 说明 |
|---|---|
#include <stdio.h> | 引入标准 I/O 库头文件 |
int main(void) | 程序入口点,返回类型为 int,void 表示不接受命令行参数 |
printf(...) | 标准输出函数,\n 为换行符 |
return 0 | 返回 0 表示程序正常退出 |
💡 提示:
main函数返回 0 是操作系统约定。返回非零值通常表示程序异常退出。
5. 编译流程
C 程序从源代码到可执行文件,经历四个阶段:
源代码(.c) → 预处理 → 编译 → 汇编 → 链接 → 可执行文件
我们可以用 GCC 分步查看每个阶段:
5.1 预处理 (Preprocessing)
gcc -E hello.c -o hello.i
展开所有 #include、#define 宏等。hello.i 文件通常非常庞大。
5.2 编译 (Compilation)
gcc -S hello.c -o hello.s
生成汇编代码(.s 文件)。
5.3 汇编 (Assembly)
gcc -c hello.c -o hello.o
生成目标文件(.o),包含机器码但尚未链接外部库。
5.4 链接 (Linking)
gcc hello.o -o hello
将目标文件与库文件链接,生成最终可执行文件。
| 阶段 | 输入 | 输出 | 命令 |
|---|---|---|---|
| 预处理 | .c | .i | gcc -E |
| 编译 | .i / .c | .s | gcc -S |
| 汇编 | .s | .o | gcc -c |
| 链接 | .o + 库 | 可执行文件 | gcc *.o |
6. GCC 常用选项
| 选项 | 说明 | 示例 |
|---|---|---|
-o <file> | 指定输出文件名 | gcc -o prog main.c |
-Wall | 启用所有常用警告 | gcc -Wall main.c |
-Wextra | 启用额外警告 | gcc -Wall -Wextra main.c |
-Werror | 将警告视为错误 | gcc -Werror main.c |
-O0 | 不优化(默认,便于调试) | gcc -O0 main.c |
-O1 / -O2 / -O3 | 优化级别递增 | gcc -O2 main.c |
-Os | 优化体积 | gcc -Os main.c |
-std=c99 | 指定 C 标准 | gcc -std=c99 main.c |
-std=c11 | 使用 C11 标准 | gcc -std=c11 main.c |
-std=c17 | 使用 C17 标准 | gcc -std=c17 main.c |
-g | 生成调试信息 | gcc -g main.c |
-pedantic | 严格遵循标准 | gcc -pedantic main.c |
-I<dir> | 添加头文件搜索路径 | gcc -I./include main.c |
-L<dir> | 添加库文件搜索路径 | gcc -L./lib main.c |
-l<lib> | 链接指定库 | gcc main.c -lm |
⚠️ 注意: 养成使用 -Wall -Wextra 的习惯,许多潜在 bug 会在编译时被发现。
7. 编辑器 / IDE 配置
7.1 VSCode
- 安装扩展 C/C++
- 安装扩展 C/C++ Extension Pack
- 按
Ctrl+Shift+P→C/C++: Edit Configurations (UI),设置编译器路径和标准
.vscode/tasks.json 示例:
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "gcc",
"args": [
"-Wall", "-Wextra", "-std=c17",
"-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}"
],
"group": { "kind": "build", "isDefault": true }
}
]
}
7.2 CLion
CLion 使用 CMake 管理项目,自动生成 CMakeLists.txt:
cmake_minimum_required(VERSION 3.20)
project(my_project C)
set(CMAKE_C_STANDARD 17)
add_executable(my_project main.c)
8. 编译多个文件
当项目由多个 .c 文件组成时,需要分别编译再链接:
gcc -c main.c -o main.o
gcc -c utils.c -o utils.o
gcc main.o utils.o -o myapp
或者一步到位:
gcc main.c utils.c -o myapp
💡 提示: 大型项目中建议使用
make或CMake管理编译流程,避免重复编译未修改的文件。
使用 Makefile 简化
CC = gcc
CFLAGS = -Wall -Wextra -std=c17 -g
myapp: main.o utils.o
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o myapp
9. C vs C++:如何选择?
| 维度 | C | C++ |
|---|---|---|
| 编译器 | gcc | g++ |
| 文件扩展名 | .c | .cpp / .cc |
| 面向对象 | 不支持 | 完整支持 |
| 标准库 | 精简(libc) | 丰富(STL) |
| 适用场景 | 操作系统、嵌入式、驱动 | 游戏引擎、GUI、大型应用 |
| 学习曲线 | 较低(语法简单) | 较高(特性繁多) |
| 内存管理 | 手动(malloc/free) | 手动 + RAII + 智能指针 |
建议:
- 初学者: 先学 C,理解指针和内存管理
- 系统编程: 使用 C(Linux 内核、嵌入式固件)
- 应用开发: 使用 C++(利用 STL 和面向对象)
10. 实际场景:编译一个小型项目
假设项目结构如下:
project/
├── main.c
├── math_utils.c
└── math_utils.h
math_utils.h:
#ifndef MATH_UTILS_H
#define MATH_UTILS_H
int add(int a, int b);
int multiply(int a, int b);
#endif
math_utils.c:
#include "math_utils.h"
int add(int a, int b)
{
return a + b;
}
int multiply(int a, int b)
{
return a * b;
}
main.c:
#include <stdio.h>
#include "math_utils.h"
int main(void)
{
int x = 3, y = 5;
printf("%d + %d = %d\n", x, y, add(x, y));
printf("%d * %d = %d\n", x, y, multiply(x, y));
return 0;
}
编译运行:
gcc -Wall -Wextra -std=c17 -o myapp main.c math_utils.c
./myapp
输出:
3 + 5 = 8
3 * 5 = 15
11. 常见编译错误
| 错误信息 | 原因 | 解决 |
|---|---|---|
undefined reference to 'main' | 缺少 main 函数 | 添加 int main(void) { ... } |
fatal error: stdio.h: No such file | 未安装 C 标准库开发包 | sudo apt install build-essential |
implicit declaration of function | 未声明函数原型 | 添加函数声明或 #include 对应头文件 |
segmentation fault | 内存访问违规 | 检查指针和数组越界 |
12. 扩展阅读
- 📖 The C Programming Language (K&R) — C 语言圣经
- 📖 C17 标准草案 (N2176)
- 📖 GCC 官方文档
- 📖 C23 新特性一览
- 📖 Compiler Explorer (godbolt.org) — 在线查看 C 代码的汇编输出