Posts 聊聊端口
Post
Cancel

聊聊端口

1. GNU 与 Linux 的关系

1. GNU 项目

  • 定义:GNU(GNU’s Not Unix)是 Richard Stallman 于 1983 年发起的自由软件计划,目标是实现一个完全自由的类 Unix 操作系统。
  • 核心组成
    • GNU Compiler Collection (GCC):编译器工具链
    • GNU C Library (glibc):标准 C 库
    • GNU Core Utilities (coreutils):基础命令(如 lscpmv 等)
    • GNU Bash (Bourne Again Shell):常用命令行 Shell
  • 局限:GNU 项目原计划开发的内核 GNU Hurd 因复杂性过高,进展缓慢,未能成为主流。

2. Linux 内核

  • 定义:Linux 是 Linus Torvalds 于 1991 年发布的自由软件内核。
  • 功能特征
    • 进程调度、内存管理、设备驱动、文件系统等核心内核功能
    • 支持模块化、可移植性与大规模并行
  • 局限:Linux 内核仅提供底层功能,本身不是完整的可用操作系统。

3. GNU/Linux 的结合

  • 结合点:Linux 内核与 GNU 提供的用户空间工具和库结合,形成一个功能完备的自由操作系统。
  • 成果:这一结合构成了主流的发行版,例如:
    • Debian / Ubuntu
    • Red Hat / Fedora
    • Arch Linux / Gentoo
  • 系统结构
    • 内核层:由 Linux 提供(硬件抽象、调度、内存管理等)
    • 用户空间层:由 GNU 提供(Shell、库、编译器、工具链等)

4. 命名争议

  • 自由软件基金会(FSF)的立场
    • “Linux”仅指内核
    • 完整的操作系统应称为 GNU/Linux,以体现 GNU 项目的贡献
  • 业界惯例
    • 在非学术与商业语境下,通常直接称为“Linux”
    • GNU/Linux 的命名主要在自由软件社区、学术出版物中使用

5. 对比总结

名称定义主要贡献局限
GNU自由软件计划,类 Unix 用户空间工具集编译器、库、Shell、核心命令工具缺少可用的内核
Linux1991 年发布的自由内核提供操作系统核心功能(调度、内存、驱动)不包含用户空间工具
GNU/LinuxGNU 工具 + Linux 内核的结合构成完整的操作系统(即各大 Linux 发行版)命名存在争议

📌 学术化结论

GNU 项目提供了操作系统用户空间的基本工具集,而 Linux 提供了内核功能。
两者结合形成了今天广泛使用的自由操作系统。在学术和自由软件语境下,应称为 GNU/Linux;然而在大多数技术实践与商业传播中,Linux 已成为事实上的简称

2. GNU 项目主要组成

1. 编译器和工具链

  • GCC(GNU Compiler Collection)
    • 支持 C、C++、Fortran、Ada、Go 等语言
    • 提供编译、优化、链接功能
  • GDB(GNU Debugger)
    • 调试器,支持多语言调试
  • Binutils(汇编器与链接器工具)
    • as 汇编器、ld 链接器、ar 静态库管理工具等
  • Make / Automake / Autoconf
    • 构建和自动化工具,帮助管理大型项目的编译和依赖

2. 系统库

  • glibc(GNU C Library)
    • 提供标准 C 库功能,系统调用封装
    • 支持文件操作、内存管理、字符串处理、线程库等
  • libstdc++
    • C++ 标准库实现
  • 其他 GNU 库
    • gmp(多精度数学库)、mpfr(高精度浮点库)、iconv(字符编码转换)等

3. Shell 和命令行工具

  • Bash(Bourne Again Shell)
    • GNU 的 shell 实现,兼容 Bourne Shell
  • 核心命令工具(Coreutils)
    • 文件操作命令:ls, cp, mv, rm
    • 文本处理命令:cat, cut, sort, uniq
    • 系统管理命令:date, df, du

4. 编辑器与开发工具

  • Emacs
    • 高度可扩展的文本编辑器
  • 其他开发工具
    • gperf(完美哈希函数生成)、texinfo(文档生成工具)

5. 操作系统内核(未广泛使用)

  • GNU Hurd
    • GNU 自己开发的微内核操作系统
    • 目标是完全自由的 Unix-like 系统,但迄今未广泛应用
  • Linux 内核 + GNU 用户空间 = GNU/Linux
    • 当前大多数 GNU 工具在 Linux 内核上运行,形成 GNU/Linux 发行版

3. 不同版本 c 工具链对比

平台编译器标准 C 库用户空间工具 / 配套工具备注
Linux / GNUGCC(GNU Compiler Collection)glibc(GNU C Library)Bash、Coreutils、GDB、Make、Autoconf 等完整 GNU 用户空间生态
WindowsMSVC(Microsoft Visual C++)MSVCRT(Microsoft C Runtime)Visual Studio 工具链、PowerShell、Windows SDKUnix 工具链需额外安装(Cygwin / MinGW)
macOS / iOSClang / LLVMApple libc(系统自有 libc)、C++ 用 libc++Xcode IDE、make、bash/zsh、BSD 版本 coreutilsBSD 血统工具,行为与 GNU 有差异
BSD 系统GCC 或 ClangBSD libc系统自带 shell、make、BSD coreutils完整开发和用户空间环境,工具与 GNU 类似但不同
嵌入式 / 轻量 LinuxGCC 或 Clangmusl、uClibcBusyBox(轻量核心命令)模块化、轻量,可裁剪,不是完整 GNU 环境

4. GNU 版本问题

摘要

  1. GNU 工具链其实不像 Linux 内核那样有一个“统一大版本”,它更像一个 松耦合的工具集合。
  2. C 版本(C89,C99) 由 gcc 编译器决定(不同版本间的默认C版本不同), glibc 决定库函数可用性。
  3. libc 与 C 语言标准版本没有直接关系,它只影响库函数可用性,而 C 标准控制语法与语言特性。
层级工具 / 组件作用 / 控制版本影响常用查看命令
系统层Linux 内核提供进程调度、内存管理、设备驱动、文件系统等操作系统核心服务决定程序运行环境与系统特性uname -r
编译器层GCC / Clang解析 C 语言语法,控制关键字和语言特性可用性,生成目标机器码决定默认 C 标准(C89/C99/C11/C17 等)、语法特性可用性gcc --version / clang --version
标准库层glibc / libc提供标准库函数和类型(如 printfmallocaligned_alloc决定可用库函数集,间接影响程序可实现语言特性ldd --version / getconf GNU_LIBC_VERSION
构建工具层Make / CMake / Autotools管理源码编译、依赖关系和目标产物生成版本差异可能影响构建流程和兼容性make --version / cmake --version
链接器 / 汇编器层Binutils (ld, as, objdump 等)汇编、链接、目标文件操作版本影响链接行为、目标文件格式支持及调试工具功能ld --version / as --version

1. 宏观理解

在 Linux C 工具链中,可以从宏观上将整个系统分为四个层级:

  1. 语言语法 → 编译器层(GCC / Clang)
    编译器决定可用的 C 语言标准(C89/C99/C11/C17 等)、关键字和数据类型。例如 inline_Bool、可变长数组(VLA)等语法特性是否可用。

  2. 库函数可用性 → 标准库层(glibc / libc)
    标准库提供函数和类型,例如 printfmallocaligned_alloc,以及 size_tFILE 等。它决定程序可调用的函数集,但不改变 C 语言语法本身。

  3. 构建流程 → 构建工具层 + 链接器层(Make / CMake / Binutils)
    管理源代码编译、依赖关系和目标产物生成,不同版本可能影响构建行为和兼容性。

  4. 运行环境 → 系统层(Linux 内核)
    提供进程调度、内存管理、设备驱动和文件系统等核心服务,决定程序能否运行。

版本关注点区分:

  • GCC / Clang → 控制 C 标准与语法特性。
  • glibc / libc → 控制可用函数和类型。
  • Make / CMake / Binutils → 控制构建与链接可靠性。
  • 内核 → 控制程序可运行性及系统特性。

2. glibc 与 C 语言标准版本关系

  1. C 标准版本
    由编译器(GCC / Clang 等)决定,控制语法、关键字和数据类型的可用性。例如 inline_Bool、可变长数组等是否可用。

  2. glibc / libc
    提供标准库函数和类型,实现 printfmallocaligned_alloc 等功能,但不改变 C 语言语法本身。

  3. 二者关系

    • 编译器根据指定 C 标准解析源码。
    • 编译后的程序调用 glibc 提供的库函数。
    • glibc 版本高,可能提供新的函数,但不会影响编译器默认的 C 标准。

5. C 工具链中 分类问题

在 Linux C 工具链中,函数来源可以分为三个主要标准:

  1. ISO C(ANSI / ISO C)
    • 全称:International Organization for Standardization C Standard
    • 定义 C 语言核心语法、关键字和标准库函数
    • 目标是保证 C 程序在不同平台上的可移植性
    • 常用函数示例:printfmallocfopenstrcpy
  2. IEEE / POSIX(Portable Operating System Interface)
    • POSIX 是 IEEE 定义的 Unix / 类 Unix 系统接口标准(IEEE 1003)
    • 提供文件操作、进程管理、信号、线程、时钟等接口
    • POSIX 补充 ISO C,使程序在类 Unix 系统中可移植
    • 常用函数示例:openreadwritepthread_create
  3. GNU / glibc 扩展
    • glibc 提供的一些非 ISO C / POSIX 标准函数
    • 提供附加功能或便利接口,例如:strdupasprintfgetline
    • 可移植性有限,仅在支持 glibc 的系统上可用

man 页分类

Linux 的 man 页面将命令和函数按用途和来源分章节:

Section描述
1Executable programs or shell commands(可执行程序或 shell 命令)
2System calls(系统调用,由内核提供)
3Library calls(库函数,在程序库中实现)
4Special files (usually devices, /dev)(特殊文件,如设备文件)
5File formats and conventions(文件格式和约定)
6Games(游戏)
7Miscellaneous(杂项,如宏、协议、标准)
8System administration commands(系统管理命令)

对应关系示例:

  • ISO C 标准函数 → man 3,例如 printf(3)malloc(3)
  • POSIX 函数 → man 2 或 man 3
    • 系统调用部分 → man 2,例如 open(2)read(2)
    • POSIX 库函数 → man 3,例如 pthread_create(3)
  • GNU 扩展函数 → man 3,并通常标注 “GNU extension”

总结

拿不同的系统对比就可以看出: Linux 支持完整的 ISO C 标准库、POSIX 接口和 GNU/glibc 扩展,macOS 支持标准库和大部分 POSIX 接口,但 GNU 扩展有限,Windows 仅支持标准库,POSIX 和 GNU 扩展不可用。

  1. ISO C / POSIX / GNU 扩展是按 标准来源 分类。
  2. man 页按 用途和提供方 分类(可执行程序 / 系统调用 / 库函数等)。
  3. 判断函数标准来源时,可结合 头文件man 页glibc 文档

6. 再聊POSIX 和 标准库

在理解 Linux 或类 Unix 系统中的函数时,必须区分标准来源、实现层次与底层依赖。主要可以分为四类:ISO C 标准函数、系统调用、POSIX 库函数和 GNU / glibc 扩展函数。值得注意的是,用户态库函数可能封装系统调用,也可能完全在用户态实现。

1️⃣ ISO C 标准函数

  • 标准来源:ISO C(ANSI C)
  • 定义:核心 C 语言语法与标准库函数,保证跨平台可移植性。
  • 典型函数printfmallocfopenstrcpy
  • 实现层次:用户态库(glibc、musl、MSVCRT 等)
  • man 页位置man 3
  • 特点
    • 平台通用,三大操作系统均支持
    • 用户态实现,无需直接调用内核(例如 strcpy
    • 部分函数(如 fopen)内部会调用系统调用,但本身仍在用户态

2️⃣ 系统调用(System Call)

  • 标准来源:操作系统内核接口,POSIX 可能规范其行为
  • 定义:由内核提供的低级接口,用于访问受保护资源(文件、进程、网络等)
  • 典型函数open(2)read(2)write(2)
  • 实现层次:内核
  • man 页位置man 2
  • 特点
    • 调用时需从用户态切换到内核态
    • POSIX 可能定义参数、返回值与行为,但不提供实现
    • 底层接口,用户态库函数可以对其进行封装以增强可用性和可移植性

3️⃣ POSIX 库函数(POSIX Library Function)

  • 标准来源:POSIX(IEEE 1003 / Portable Operating System Interface)
  • 定义:用户态接口函数,提供跨类 Unix 系统的可移植功能
  • 典型函数pthread_create(3)sem_init(3)sigaction(3)
  • 实现层次:用户态库(glibc、libpthread 等)
  • man 页位置man 3
  • 特点
    • 有时调用系统调用,有时完全在用户态实现
    • 保证跨 Unix 系统一致性
    • 不是 ISO C 标准库函数

4️⃣ GNU / glibc 扩展函数

  • 标准来源:GNU / glibc 提供的扩展
  • 定义:标准库和 POSIX 之外的增强函数
  • 典型函数asprintf(3)getline(3)strdup(3)
  • 实现层次:用户态库实现
  • man 页位置man 3,标注 “GNU extension”
  • 特点
    • 仅在 Linux glibc 系统可用
    • 提供便利函数或增强功能
    • 不保证跨平台可移植性

示例:fopen

  • fopen("file.txt", "r") 是用户态库函数 → man 3
  • 内部实现:
    1. 调用 open("file.txt", O_RDONLY) 系统调用进入内核态
    2. 分配缓冲区,初始化 FILE* 结构 → 用户态库操作
    3. 返回 FILE* 给用户
  • 结论:虽然 fopen 需要内核提供底层支持,但它本身运行在用户态,是库函数,而非系统调用。

总结表

分类标准来源实现层次man 页典型函数可移植性
ISO CISO C用户态库3printfmalloc跨平台
系统调用内核 / POSIX 定义内核2openread类 Unix 系统
POSIX 函数POSIX用户态库3pthread_createsem_init类 Unix 系统
GNU 扩展GNU / glibc用户态库3asprintfgetlineLinux 特有

关键逻辑:

  • 系统调用是操作系统提供的底层接口;
  • 用户态库函数可能封装系统调用,也可能完全在用户态实现;
  • ISO C、POSIX、GNU 扩展的划分反映标准来源与可移植性;
  • man 页章节反映实现层次,而非标准归属。

使用逻辑

标准库(ISO C)应优先使用,当程序需要跨平台可移植性且不依赖操作系统底层特性时,如 printf、malloc、fopen 等函数,它们运行在用户态并封装了必要的系统调用。

当程序目标平台为类 Unix 系统且需要操作系统特性(线程、信号、IPC 等)时,可使用 POSIX 函数,如 pthread_create、open(2);若需要精细控制内核资源或追求性能,则直接使用系统调用,如 read(2)、mmap(2),尽管可移植性有限。

内核是单独的一套api了, 后面有空再写。

结尾

很多函数既在 ISO C 里定义,又被 POSIX 采纳,例如 fopen(),man page 并不会标注“这是 ISO C 的还是 POSIX 的”,所以看 man page 很容易混淆。

例如, 在 C/C++ 中,<signal.h> 提供了信号处理接口,但不同标准和实现支持的功能范围不同,容易混淆。下面按层级梳理:


1️⃣ ISO C 标准(C89 / C99 / C11)

  • 功能范围:最基本的信号接口,只保证少数几个信号存在:
    • SIGABRT、SIGFPE、SIGILL、SIGINT、SIGSEGV、SIGTERM
  • 特点
    • 跨平台通用
    • 信号概念有限,不能依赖高级功能

2️⃣ POSIX 标准(IEEE 1003.1)

  • 功能范围
    • 在 ISO C 基础上扩展信号功能,专注 Unix/Linux 系统
    • 增加更多信号:SIGHUP、SIGQUIT、SIGPIPE、SIGALRM、SIGUSR1、SIGUSR2 等
    • 提供可靠信号处理接口和信号屏蔽机制
  • 特点
    • Unix/Linux 平台通用
    • 支持信号屏蔽、信号队列、实时信号
    • 推荐使用可靠信号接口代替旧式信号函数

3️⃣ GNU / glibc 扩展(Linux 特有)

  • 功能范围
    • 对 POSIX 信号做扩展,支持更多实时信号:SIGRTMIN ~ SIGRTMAX
    • 提供额外工具函数,如发送带数据的信号、打印信号信息
    • 对旧式信号函数做可重入封装,兼容 POSIX
  • 特点
    • 仅 Linux 平台可用
    • 移植到非 GNU 系统可能不支持

总结表

分类标准/实现功能范围代表接口 / 函数
ISO CANSI C基本信号signal(), raise()
POSIXIEEE 1003.1扩展信号、可靠信号、屏蔽、实时信号sigaction(), sigprocmask(), sigpending()
GNU/glibcLinux-specific实时信号扩展、信号队列、额外工具sigqueue(), psiginfo()

💡 理解原则

一共可以分为这三大类, 若需要新增一类, 那就是外部第三方库头文件了

  1. 跨平台 C 程序 → 只用 ISO C 信号接口
  2. Unix/Linux 开发 → 推荐使用 POSIX 可靠信号接口
  3. Linux 专用高级功能 → 可以使用 glibc 扩展

1️⃣ ISO C

  • 引用库:标准 C 库(libc 的核心部分)
  • 头文件#include <signal.h>
  • 实现:ISO C 定义最基本的信号接口(signal(), raise()),不依赖操作系统特有功能
  • 可移植性:跨平台,可在 Windows、Linux、macOS 等都用

2️⃣ POSIX

  • 引用库:POSIX 层的 libc 实现
  • 头文件:同样是 #include <signal.h>(glibc 会统一实现 ISO C + POSIX)
  • 实现:在 ISO C 基础上增加了可靠信号接口、信号屏蔽、实时信号等
  • 可移植性:Unix-like 系统通用(Linux、FreeBSD、macOS 等),Windows 不支持 POSIX 信号接口

3️⃣ GNU / glibc

  • 引用库:glibc(GNU C Library)
  • 头文件#include <signal.h>
  • 实现:POSIX 接口 + Linux 特有扩展,如实时信号、sigqueue()
  • 可移植性:仅 Linux 可用,移植到非 GNU 系统可能不支持某些扩展
This post is licensed under CC BY 4.0 by the author.

Contents

Trending Tags