嵌入式面试总结(二十一)——C语言关键字

前言

在嵌入式C语言开发面试中,对关键字的深入理解是考察基本功的重要环节。C语言的关键字不仅定义了语言的语法结构,更直接关系到程序的效率、内存布局和可移植性。本文将对嵌入式开发中高频出现且易混淆的C语言关键字进行系统性梳理和总结,帮助读者在面试中从容应对。

面试重点提示:

  • 理解而非死记:面试官更关注你对关键字底层机制(如存储类别、生命周期、作用域、编译器优化影响)的理解,而非简单的定义背诵。
  • 场景化应用:结合嵌入式特有场景(如寄存器访问、中断处理、内存受限环境、多任务共享)来阐述关键字的实际价值。
  • 辨析易混点 :重点区分 static 的不同用法、const#define 的优劣、volatile 的必要性及其与 const 的组合、extern 与链接属性等。
  • 关注底层影响:理解关键字对程序行为(如性能、安全性、可维护性)和内存布局(如数据段、栈、寄存器)的实际影响。

目录

本文详细梳理了嵌入式C语言开发面试中常见的关键字,以下是各章节导航:

  • 1. 存储类别关键字
    • 1.1 auto
    • 1.2 register
    • 1.3 static
    • 1.4 extern
  • 2. 类型限定符
    • 2.1 const
    • 2.2 volatile
    • 2.3 restrict (C99)
  • 3. 循环与跳转控制
    • 3.1 break 与 continue
    • 3.2 goto
  • 4. 复杂类型与运算符
    • 4.1 sizeof
    • 4.2 typedef
  • 5. 嵌入式特有重点
    • 5.1 volatile 与 const 的组合
    • 5.2 位域 (bit-field)
  • 6. 面试真题与解析
  • 7. 总结

点击上方标题可快速跳转到对应章节。

1. 存储类别关键字

存储类别关键字决定了变量的存储位置、生命周期和链接属性,是理解C程序内存布局和运行机制的基础。在嵌入式开发中,合理使用这些关键字对优化内存使用、提升程序效率和保证代码可维护性至关重要。

1.1 auto

auto 关键字用于声明自动变量,即局部变量。在函数内部定义的变量,默认就是 auto 类型,因此现代C编程中通常省略不写。

c 复制代码
void func() {
    auto int a = 10; // 等同于 int a = 10;
    int b = 20;      // 默认就是 auto
}

面试要点:理解其"自动"的含义------进入作用域时自动分配内存(通常在栈上),离开作用域时自动释放。这是C语言中最常见的变量存储方式。

1.2 register

register 建议编译器将变量存储在CPU寄存器中,以提高访问速度。编译器有权忽略此建议。

c 复制代码
register int counter; // 建议将counter放入寄存器

面试要点

  • 不能对 register 变量取地址(&),因为寄存器没有内存地址。
  • 嵌入式场景中,对频繁访问的循环控制变量使用 register 可能带来性能提升,尤其是在资源受限的微控制器上。
  • 现代编译器优化能力很强,通常能自动识别热点变量并放入寄存器,因此显式使用 register 的场景已不多见。

1.3 static

static 关键字用途广泛,是面试必考点。其含义根据修饰对象的不同而有所区别。

c 复制代码
// 1. 修饰局部变量:延长生命周期至整个程序运行期,作用域不变
void count() {
    static int call_count = 0; // 只初始化一次,函数退出后值保留
    call_count++;
    printf("被调用 %d 次\n", call_count);
}

// 2. 修饰全局变量/函数:限制作用域仅在当前源文件内
// file1.c
static int hidden_var; // 仅在file1.c中可见,内部链接
static void helper() { ... } // 仅在file1.c中可见

核心区别

  • 修饰局部变量:延长生命周期至整个程序运行期,作用域不变(仍只在函数内可见)。变量存储在静态存储区(数据段),只初始化一次。
  • 修饰全局变量/函数:限制其作用域仅在当前源文件内,避免命名冲突(内部链接)。这有助于实现模块化设计和信息隐藏。

面试要点

  • 区分生命周期(变量存在的时间)与作用域(变量可见的范围)。
  • 理解 static 变量在内存中的位置(数据段),与 auto 变量(栈)的区别。
  • 掌握 static 在嵌入式多文件项目中的实际应用,如模块内部状态保持、私有函数封装等。

1.4 extern

extern 用于声明(而非定义)一个在其他文件中定义的全局变量或函数,表示外部链接。它是实现多文件编程和模块间通信的关键。

c 复制代码
// file1.c - 定义全局变量和函数
int global_var = 100;          // 定义,分配存储空间
void func() { 
    // 函数实现
}

// file2.c - 使用其他文件中定义的变量和函数
extern int global_var; // 声明,告诉编译器变量在别处定义
extern void func();    // 函数声明

int main() {
    global_var = 200;  // 实际修改的是file1.c中定义的变量
    func();            // 调用file1.c中定义的函数
    return 0;
}

声明 vs. 定义

  • 声明(Declaration):告诉编译器"这个符号存在,但可能在其他地方定义"。不分配存储空间。一个变量或函数可以被多次声明。
  • 定义(Definition):为变量分配存储空间或为函数提供实现体。一个变量或函数只能被定义一次。

面试要点

  • 理解声明与定义的本质区别,避免重复定义错误。
  • 掌握多文件编程中 extern 的正确用法,特别是头文件(.h)中通常放声明,源文件(.c)中放定义。
  • 了解 extern "C" 在C++中用于链接C语言函数的作用。

嵌入式开发中的实际考虑:在嵌入式系统中,合理使用存储类别关键字可以:

  1. 优化内存使用:auto变量随用随放,static变量长期占用内存。
  2. 控制访问范围:static限制作用域,提高模块独立性。
  3. 管理变量生命周期:根据需求选择auto、static或全局变量。
  4. 优化性能:register提示编译器优化,但需谨慎使用。

2. 类型限定符

类型限定符用于为变量或指针添加额外的语义约束,指导编译器进行更严格的类型检查或优化。在嵌入式开发中,它们直接影响代码的安全性、可移植性和执行效率,是面试中的高频考点。

2.1 const

const 用于定义只读变量,修饰后值不可变。编译器会将其放入只读存储区(如ROM)。

c 复制代码
const int MAX_SIZE = 1024; // 必须初始化
const int *p;       // 指向常量的指针,指针可变,指向的内容不可变
int * const p;      // 常量指针,指针不可变,指向的内容可变
const int * const p;// 指向常量的常量指针,两者都不可变

面试要点

  • 与 #define 宏的区别:const 有类型检查,占用存储空间,可调试;#define 是预处理阶段的文本替换,无类型检查,不占存储空间,调试时不可见。
  • 嵌入式应用:常用于定义硬件寄存器地址(只读)、配置参数、查找表等,确保数据不被意外修改。
  • 指针修饰位置:牢记"左定值,右定向"原则------const 在 * 左边修饰指向的对象,在 * 右边修饰指针本身。

2.2 volatile

volatile 是嵌入式面试的绝对核心。它告诉编译器,该变量的值可能被程序之外的代理(如硬件、中断、其他线程)改变,禁止编译器对其做优化(如缓存到寄存器、删除"冗余"读取)。

c 复制代码
volatile uint32_t *reg = (uint32_t*)0x40021000; // 硬件寄存器地址
while (*reg & 0x01) { // 每次循环都必须从内存读取reg的值
    // 等待标志位
}

面试要点

  • 必须使用 volatile 的场景
    1. 硬件寄存器映射:寄存器的值由硬件改变。
    2. 中断服务程序修改的全局变量:主循环中访问的变量可能被ISR修改。
    3. 多线程共享变量(无锁访问时):变量可能被其他线程修改。
  • 与 const 的组合volatile const uint32_t READ_ONLY_REG; 表示只读的硬件寄存器(如状态寄存器)。
  • 优化影响:未使用 volatile 可能导致编译器错误优化,如将循环中的寄存器读取优化为一次读取,造成死循环或数据不同步。

2.3 restrict (C99)

restrict 仅用于指针,向编译器承诺,在该指针的生命周期内,只有它(或由其衍生的指针)会访问其所指向的对象。这允许编译器进行更激进的优化(如向量化、指令重排)。

c 复制代码
void copy(int *restrict dest, const int *restrict src, int n) {
    // 编译器可假设 dest 和 src 指向的内存区域不重叠,可能使用向量指令优化
    for (int i = 0; i < n; i++) {
        dest[i] = src[i];
    }
}

面试要点

  • 优化提示:restrict 是一个优化提示,不是强制约束。编译器可能忽略它,但若承诺被违反(指针实际重叠),将导致未定义行为。
  • 适用场景:常用于高性能计算、DSP、图像处理等需要明确指针不重叠以启用向量指令的场合。
  • 嵌入式考量:在资源受限的嵌入式系统中,合理使用 restrict 可以提升关键循环的性能,但必须确保指针确实不重叠,否则可能引入难以调试的错误。

类型限定符综合对比

关键字 主要作用 嵌入式典型应用 注意事项
const 定义只读变量,防止意外修改 只读寄存器、配置常量、查找表 与指针结合时注意修饰位置
volatile 禁止编译器优化,确保每次从内存读取 硬件寄存器、ISR共享变量、多线程变量 滥用可能降低性能,但该用时必须用
restrict 提示指针不重叠,允许激进优化 高性能计算、DSP算法、图像处理 违反承诺导致未定义行为

3. 循环与跳转控制

循环与跳转控制关键字直接决定了程序的执行流程。在嵌入式开发中,对流程的精确控制尤为重要,尤其是在实时性要求高、资源受限的场景下。理解这些关键字的底层行为,有助于编写出更高效、更健壮的代码。

3.1 break 与 continue

breakcontinue 是控制循环执行流程的两个核心关键字。

  • break :立即终止当前所在的循环(for, while, do-while)或 switch 语句,程序继续执行循环或 switch 之后的代码。
  • continue:跳过当前循环体中剩余的语句,直接进入下一次循环的条件判断(for循环会先执行增量表达式)。

面试要点

  • 行为区别break 是"跳出",continue 是"跳过本轮"。
  • 嵌套循环breakcontinue 只影响其所在的最近一层循环。
  • 嵌入式场景
    • break:常用于满足某个条件(如接收到特定指令、检测到错误)时立即退出轮询或等待循环。
    • continue:用于跳过对某些无效或无需处理的数据包、传感器采样值的处理,提高循环效率。
c 复制代码
// 示例:使用 break 和 continue 处理传感器数据流
void process_sensor_data(uint8_t *buffer, int len) {
    for (int i = 0; i < len; i++) {
        // 遇到结束符,提前退出循环
        if (buffer[i] == 0xFF) {
            printf("检测到数据包结束符。\n");
            break;
        }

        // 跳过无效数据(例如,保留字节或填充值)
        if (buffer[i] == 0x00 || buffer[i] == 0xFE) {
            printf("跳过无效数据 0x%02X。\n", buffer[i]);
            continue;
        }

        // 处理有效数据
        valid_data_process(buffer[i]);
    }
}

3.2 goto

goto 语句允许程序无条件跳转到同一函数内的标签处。由于其会破坏程序的结构化,在一般应用开发中不鼓励使用。然而,在嵌入式系统开发,尤其是底层驱动和错误处理中,它有其特定的用武之地。

合理使用场景(嵌入式)

  1. 集中式错误处理与资源清理 :在初始化多个硬件模块或分配多项资源的函数中,任何一步失败都需要回滚之前的所有操作。使用 goto 可以跳转到统一的错误处理标签,避免重复的清理代码。
  2. 跳出深层嵌套 :在深度嵌套的循环或条件判断中,有时需要一次性跳出多层。虽然可以设置标志位,但 goto 有时更为清晰直接。

必须避免的陷阱

  • 向前跳转进入变量作用域:跳转到变量定义之前,会导致变量未初始化。
  • 制造"面条代码" :滥用 goto 进行随意的前后跳转,会使程序逻辑支离破碎,难以理解和维护。
c 复制代码
// 示例:使用 goto 进行集中错误处理(嵌入式驱动初始化)
int device_init(void) {
    int fd_uart, fd_spi, fd_i2c;
    void *dma_buffer = NULL;

    // 1. 初始化 UART
    fd_uart = uart_open("/dev/ttyS0");
    if (fd_uart < 0) {
        perror("UART 打开失败");
        goto err_exit; // 第一步失败,直接跳转到清理
    }

    // 2. 初始化 SPI
    fd_spi = spi_open("/dev/spidev0.0");
    if (fd_spi < 0) {
        perror("SPI 打开失败");
        goto err_uart; // 第二步失败,关闭已打开的 UART
    }

    // 3. 分配 DMA 缓冲区
    dma_buffer = malloc(DMA_BUFFER_SIZE);
    if (dma_buffer == NULL) {
        perror("DMA 缓冲区分配失败");
        goto err_spi; // 第三步失败,关闭 SPI 和 UART
    }

    // 4. 初始化 I2C (可选,失败不影响主要功能,但需记录日志)
    fd_i2c = i2c_open("/dev/i2c-1");
    if (fd_i2c < 0) {
        fprintf(stderr, "警告: I2C 初始化失败,部分功能受限。\n");
        // 不跳转,继续执行
    }

    // 所有初始化成功
    return 0; // 成功返回

// 错误处理标签(按打开顺序的逆序清理)
err_spi:
    spi_close(fd_spi);
err_uart:
    uart_close(fd_uart);
err_exit:
    if (dma_buffer) free(dma_buffer); // 释放可能已分配的缓冲区
    return -1; // 失败返回
}

面试要点

  • 承认其合理性 :在嵌入式系统,尤其是资源清理和错误处理中,goto 可以使代码更简洁、更安全。
  • 强调使用准则:只允许向后跳转(跳转到函数后面的标签),且仅用于错误处理等有限场景。坚决反对向前跳转和随意跳转。
  • 对比其他语言 :了解 C++/Java 等语言的 RAII 机制或 try-catch-finally 如何更优雅地解决资源清理问题,并理解在纯 C 环境中 goto 的不可替代性。

4. 复杂类型与运算符

4.1 sizeof

sizeof 是运算符,不是函数。用于计算类型或对象所占用的内存字节数。在编译时求值。

c 复制代码
int arr[10];
size_t size1 = sizeof(int);    // 通常是4
size_t size2 = sizeof(arr);    // 10 * sizeof(int) = 40
size_t size3 = sizeof(&arr);   // 指针的大小,通常是4或8

面试要点 :区分 sizeof(数组名)sizeof(指针)

4.2 typedef

typedef 用于为现有类型创建别名,提高代码可读性和可移植性。

c 复制代码
typedef unsigned int uint32_t; // 定义平台无关的32位无符号整数
typedef int (*FuncPtr)(int, int); // 定义函数指针类型

面试要点:与 #define 的区别(typedef 是类型别名,有类型检查;#define 是文本替换)。

5. 嵌入式特有重点

5.1 volatile 与 const 的组合

这是嵌入式硬件访问的经典模式。

  • volatile const:只读硬件寄存器(如状态寄存器)。
  • volatile:可读可写硬件寄存器(如数据寄存器)。
c 复制代码
#define STATUS_REG (*(volatile const uint32_t *)0x40000000)
#define DATA_REG   (*(volatile uint32_t *)0x40000004)

5.2 位域 (bit-field)

使用 struct 定义位域,可以精确控制结构体成员的位宽,常用于访问硬件寄存器中的特定位。

c 复制代码
typedef struct {
    unsigned int enable : 1;   // 1 bit
    unsigned int mode   : 3;   // 3 bits
    unsigned int        : 4;   // 4 bits 保留
    unsigned int status : 8;   // 8 bits
} ControlReg;

面试要点:位域的存储依赖编译器实现(字节序、位序),可移植性需注意。

6. 面试真题与解析

本节精选嵌入式C语言面试中关于关键字的典型真题,并提供详细解析和扩展思考,帮助读者深入理解概念并掌握答题技巧。

Q1: static 全局变量和普通全局变量有什么区别?

A1: static 全局变量的作用域仅限于定义它的源文件,在其它文件中不可见(内部链接),避免了命名冲突。普通全局变量默认具有外部链接,可以通过 extern 在其他文件中访问。

扩展思考:在嵌入式多模块项目中,使用 static 全局变量可以封装模块内部状态,提高模块的独立性和可维护性。例如,一个 UART 驱动模块内部的状态机变量应声明为 static,避免被其他模块意外修改。

Q2: const int *p 和 int * const p 有什么区别?

A2 : const int *p 是指向常量的指针,指针 p 本身可以指向别的地址,但不能通过 p 修改其所指向的整数值。int * const p 是常量指针,指针 p 本身一旦初始化就不能再指向其他地址,但可以通过 p 修改其所指向的整数值。

记忆技巧:记住"左定值,右定向"。const 在 * 左边,修饰的是指向的值(定值);const 在 * 右边,修饰的是指针本身(定向)。

Q3: 什么情况下必须使用 volatile?请举例说明。

A3: 三种典型场景:1) 硬件寄存器映射(值由硬件改变);2) 中断服务程序修改的全局变量;3) 多线程环境中被多个线程共享的变量(无锁访问时)。例如,在轮询等待硬件标志位时,必须将指向标志寄存器的指针声明为 volatile,否则编译器可能将读取操作优化掉,导致死循环。

深入追问:面试官可能会进一步问:"如果忘记加 volatile,编译器具体会做什么优化?" 答案是:编译器可能将多次读取优化为一次,或将变量值缓存到寄存器,导致程序无法感知外部的变化。

Q4: register 关键字在现代编译器中还有必要使用吗?为什么?

A4: 在现代编译器中,显式使用 register 关键字的必要性大大降低。因为现代编译器(如 GCC、Clang)的优化器非常智能,能够自动分析代码的热点,将频繁使用的变量分配到寄存器中。程序员手动指定 register 反而可能干扰编译器的优化决策。此外,register 变量不能取地址,限制了其灵活性。在嵌入式开发中,更应关注算法优化和内存访问模式,而非依赖 register 提示。

Q5: 请解释 sizeof 在编译时和运行时的行为,并举例说明 sizeof(数组) 和 sizeof(指针) 的区别。

A5: sizeof 是运算符,在编译时求值(除了 C99 中的变长数组)。它返回类型或对象所占用的内存字节数。

c 复制代码
int arr[10];
int *ptr = arr;

printf("sizeof(arr) = %zu\n", sizeof(arr));   // 输出 40 (假设 int 为 4 字节)
printf("sizeof(ptr) = %zu\n", sizeof(ptr));   // 输出 4 或 8 (指针大小)
printf("sizeof(*ptr) = %zu\n", sizeof(*ptr)); // 输出 4 (int 的大小)

关键区别:当数组名作为 sizeof 的操作数时,它代表整个数组的大小;而当数组名退化为指针后,sizeof 返回的是指针本身的大小。这是面试中常见的陷阱。

Q6: 在嵌入式错误处理中,goto 语句有何合理用途?使用时需遵循什么原则?

A6: 在嵌入式 C 编程中,goto 语句可用于实现集中式的错误处理和资源清理,尤其是在初始化多个硬件资源(如 UART、SPI、DMA 缓冲区)时。如果某一步失败,可以跳转到统一的清理标签,按打开顺序的逆序释放已分配的资源,避免代码重复和遗漏。

使用原则:1) 只允许向后跳转(跳转到函数后面的标签);2) 仅用于错误处理等有限、结构清晰的场景;3) 绝对禁止向前跳转或制造复杂的跳转逻辑("面条代码")。

Q7: typedef 和 #define 在定义类型别名时有何本质区别?

A7: typedef 是 C 语言的关键字,用于为现有类型创建新的类型别名,它在编译阶段被处理,具有类型检查。而 #define 是预处理指令,进行简单的文本替换,没有类型检查,容易引入错误。

c 复制代码
typedef int* IntPtr;      // IntPtr 是一个指向 int 的指针类型
#define IntPtr int*       // 文本替换

IntPtr a, b;              // typedef: a 和 b 都是 int*; #define: a 是 int*, b 是 int

因此,在定义类型别名时,应优先使用 typedef,以提高代码的类型安全性和可读性。

Q8: 请说明 restrict 关键字的作用,并指出在什么场景下使用它需要特别小心。

A8: restrict 关键字(C99)用于修饰指针,向编译器承诺:在该指针的生命周期内,只有它(或由其衍生的指针)会访问其所指向的内存区域。这允许编译器进行更激进的优化,如指令重排、向量化。

需小心的场景:当指针实际指向的内存区域存在重叠(aliasing)时,绝对不能使用 restrict。因为编译器基于"不重叠"的假设进行的优化,如果假设被违反,将导致未定义行为和难以调试的错误。在嵌入式 DSP 或图像处理算法中,使用 restrict 前必须确保数据缓冲区是独立的。

Q9: 如何理解"位域(bit-field)的可移植性问题"?

A9 : 位域的可移植性问题主要体现在两个方面:1) 存储顺序(字节序/位序) :不同处理器架构(大端/小端)对位域在内存中的布局方式可能不同。2) 编译器实现差异:C 标准未明确规定位域的内存布局细节(如位域是否可跨存储单元、位域的对齐方式),不同编译器可能有不同的实现。因此,在需要跨平台或与硬件寄存器精确映射的代码中,使用位域需谨慎,通常建议使用位掩码和移位操作来替代,以保证可移植性和精确控制。

Q10: 结合嵌入式场景,谈谈 auto、static 和全局变量在内存布局和生命周期上的差异。

A10:

  • auto(局部变量):存储在栈(stack)上。生命周期与函数调用同步,进入函数时分配,函数返回时释放。内存高效但生命周期短。
  • static(局部或全局):存储在静态存储区(数据段)。生命周期贯穿整个程序运行期,只初始化一次。static 局部变量作用域仍限于函数内,但值在调用间保持;static 全局变量作用域限于文件内。
  • 普通全局变量:存储在静态存储区(数据段)。生命周期为整个程序运行期,具有外部链接(除非用 static 修饰)。

嵌入式考量:在资源受限的系统中,应避免滥用全局和 static 变量(长期占用内存),合理使用 auto 变量以节省 RAM。同时,利用 static 控制作用域,提高模块化程度。

7. 总结

掌握C语言关键字是嵌入式工程师的基本功。面试中,面试官不仅考察你是否知道这些关键字,更关注你能否理解其底层含义、适用场景以及可能带来的影响(如性能、安全性)。建议结合具体的嵌入式应用场景(如寄存器操作、中断处理、内存受限环境)来深入理解并灵活运用这些关键字。

核心要点回顾:

  • 存储类别关键字 :理解 autoregisterstaticextern 对变量生命周期、作用域和链接属性的影响,是优化内存布局和模块化设计的基础。
  • 类型限定符const 确保数据只读,volatile 防止编译器错误优化,restrict 提示指针不重叠以启用优化。三者组合(如 volatile const)是硬件访问的经典模式。
  • 流程控制break/continue 控制循环流程,goto 在嵌入式错误处理中仍有其合理用途,但需严格遵循向后跳转原则。
  • 类型与运算符sizeof 在编译时求值,区分数组与指针;typedef 提升类型安全与可读性,优于 #define
  • 嵌入式特有 :位域(bit-field)用于寄存器位级访问,但需注意可移植性;volatileconst 的组合是访问硬件寄存器的标准做法。

面试策略建议:

  1. 理解优先于记忆:不要死记硬背定义,要从内存布局、编译器行为、硬件交互等底层机制出发解释关键字。
  2. 场景化举例 :针对每个关键字,准备1-2个嵌入式典型应用场景(如 volatile 用于状态寄存器轮询,static 用于模块内部状态封装)。
  3. 辨析易混点 :重点区分 static 修饰局部与全局的不同含义、const int *pint * const p 的差异、register 在现代编译器中的实际价值。
  4. 关注优化与安全 :理解关键字对编译器优化的影响(如 volatile 防止优化、restrict 启用优化)以及对代码安全性、可维护性的贡献。

实践与提升:

理论学习之外,建议在真实项目或模拟环境中实践:

  • 编写驱动代码,体验 volatile 在硬件寄存器访问中的必要性。
  • 构建多文件项目,运用 staticextern 管理模块可见性。
  • 分析反汇编代码,观察 constregister 等关键字对生成指令的影响。
  • 阅读优秀开源嵌入式项目(如 RT-Thread、FreeRTOS 驱动代码),学习关键字的实际用法。

最终,对关键字的深刻理解将帮助你写出更高效、更健壮、更可维护的嵌入式C代码,在面试和实际工作中都能从容应对。

相关推荐
W_326001 小时前
Python-OpenCV:库、环境搭建、图片与摄像头解析
开发语言·图像处理·python·opencv·机器学习
zhy295631 小时前
在 QAIRT Genie SDK 上部署 Llama 3.2 1B 模型:从环境准备到 C++ 推理
开发语言·c++·llama
爱跳舞的烤冷面1 小时前
自学嵌入式第N天(Linux篇——文件编程)
java·开发语言·前端
Escalating_xu2 小时前
【Linux】进程间通信:从匿名管道、FIFO 到共享内存、消息队列与信号量
java·linux·面试
caimouse2 小时前
ReactOS 图形系统分析(33):字体子系统 — font.c
c语言·开发语言·reactos
不悔哥2 小时前
Tinyftp 源码学习笔记:3000 行 C 实现的 FTP 服务器
服务器·c语言·网络·tcp/ip
cxr8282 小时前
HyperMind Lab M1 架构地基 Implementation Plan <二>
开发语言·人工智能·架构
灵晔君2 小时前
【Linux】进程控制(一)——进程创建、进程终止与进程等待
linux·c语言·算法
特立独行的猫a2 小时前
Tauri v2的Rust应用 → HarmonyOS(鸿蒙 PC)移植30分钟速成指南
开发语言·rust·harmonyos·tauri·移植·鸿蒙pc