面试八股:C语言的预处理和类型定义

目录

一,define 和 typedef 的区别

1.1 概念

1.2 用法和区别

1.3 优缺点

二,常见宏的使用

2.1 宏的定义和使用

2.3 注意事项

三,# 和 ## 区别

3.1 # 操作符:字符串化

3.2 ## 操作符:连接符

3.3 区别

四,offsetof 的作用与实现

4.1 定义

4.2 实现原理

五,container_of 的实现

5.1 定义

5.2 原理

六,typeof

七,C/C++ 最佳实践


C 语言作为一门经典的系统编程语言,它的预处理器指令和类型定义

为开发者提供了强大的灵活性

本文档主要探讨:

  1. C 语言中 define 和 typedef 的区别
  2. 常见宏的使用
  3. 预处理器操作符 # 和 ##
  4. offsetof,container_of 和 typeof 的实现

一,define 和 typedef 的区别

1.1 概念

  • define:
    • C 预处理指令,用于定义宏
    • 编译前的预处理阶段将宏名替换为对应的内容,是一种文本替换机制
    • 可以定义常量,函数宏
#define PI 3..14159 // 常量宏
#define MAX(a, b) ((a) > (b) ? (a) : (b)) // 函数宏
  • typedef:
    • C 语言关键字,为现有类型定义别名
    • 编译阶段起作用,是一种类型定义机制,用于简化复杂声明

ulong 是 unsigned long 的别名,Point 是结构体的别名

typedef unsigned long ulong;
typedef struct {
    int x;
    int y;
} Point;

1.2 用法和区别

  • 作用阶段:
    • define 在预处理阶段文本替换
    • typedef 在编译阶段类型解析
  • 功能差异:
    • define 只是简单的文本替换,不涉及类型检查,可能导致错误
    • typedef 定义的是类型别名,编译器会进行类型检查
  • 适用场景:
    • define 定义常量或简单的宏
    • typedef 可以为复杂类型定义别名(如结构体,指针)
#define INT_PTR int* // 文本替换
typedef int* IntPtr; // 类型别名

INT_PTR a, b; // 展开后为 int* a, b;  只有 a 是指针,b 是 int
IntPtr c, d; // c 和 d 都是 int* 类型

1.3 优缺点

  • define:灵活,可定义常量和宏,但缺乏类型检查,易出错
  • typedef:类型安全,提高可读性,仅限于类型别名

二,常见宏的使用

2.1 宏的定义和使用

宏通过 define 定义,用于在编译前,进行文本替换

  • 常量宏
#define BUFFER_SIZE 1024
char buffer[BUFFER_SIZE];
  • 调试宏
#ifdef DEBUG // 如果已定义 DEBUG 宏
#define LOG(msg) printf("Debug: %s\n", msg) // 执行这行
#else // 如果未定义
#define LOG(msg) // 为空
#endif // 结束条件编译
LOG("Function started");
  • 函数宏
#define MIN(a, b) ((a) < (b) ? (a) : (b))
int smaller = MIN(5, 10);

2.3 注意事项

  • 避免副作用:函数宏参数可能多次求职,需要加括号保护
  • 代码膨胀:复杂的宏,会导致编译后代码体积增大

三,# 和 ## 区别

3.1 # 操作符:字符串化

  • 作用:将宏参数转化为字符串字面量,用于调试
#define PRINT_VAR(var) printf(#var " = %d\n", var)
int x = 42;
PRINT_VAR(x); // 输出 x = 42

3.2 ## 操作符:连接符

  • 作用:两个标识符被连接,成为新的标识符,用于代码生成
#define CONCAT(prefix, suffix) prefix ## suffix
int CONCAT(var_, 1) = 100; // 展开为 int var_1 = 100;

3.3 区别

  • 区别:# 转为字符串,## 连接标识符
  • 应用:# 用于日志,## 生成变量名

四,offsetof 的作用与实现

4.1 定义

offsetof 是 C 标准宏,定义在 <stddef.h> 中,用于计算按结构体成员的偏移量

#include <stddef.h>
#include <stdio.h>
struct Example { char a; int b; double c; };
int main() {
    printf("Offset of a: %zu\n", offsetof(struct Example, a)); // Offset of a: 0
    printf("Offset of b: %zu\n", offsetof(struct Example, b)); // Offset of b: 4
    return 0;
}

4.2 实现原理

type 是结构体,member 是 type 的一个成员

#define offsetof(type, member) ((size_t)&(((type *)0)->member))
  • 解释:
    • 将 0 转化成结构体指针
    • 假设结构体在地址 0,然后访问成员 member 的地址
    • 由于结构体起点是 0,成员的地址就是偏移量
    • 最后转为 size_t 类型返回
    • 这个过程在编译时完成,不真正访问内存,只是利用编译器计算偏移
  • 使用场景:
    • 内存布局:调试 OR 优化内存对齐
    • 指针操作:结合指针访问成员

五,container_of 的实现

5.1 定义

container_of 用于 Linux 内核,通过成员指针反向获取结构体指针

#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
  struct Person { int id; char name[20]; };
  int main() {
      struct Person p = {1, "Alice"};
      char *name_ptr = p.name;
      struct Person *person_ptr = container_of(name_ptr, struct Person, name);
      printf("ID: %d\n", person_ptr->id);
      return 0;
  }

5.2 原理

  • 原理:offsetof 获取偏移量,成员指针 - 偏移量得到结构体地址
  • 使用场景:
    • 嵌入式:通过成员访问结构体
    • 数据结构:链表中反向获取节点

六,typeof

定义

  • typeof 是 GCC 扩展关键字,用于获取表达式类型,C++ 用 decltype
  int x = 10;
  typeof(x) y = 20; // 等价于 int y = 20;

应用:用于宏,确保类型一致性

  #define SWAP(a, b) do { typeof(a) temp = a; a = b; b = temp; } while(0)
  int x = 1, y = 2;
  SWAP(x, y);

七,C/C++ 最佳实践

    • 最小化使用:优先 const 代替宏
    • 括号保护
  • 类型定义
    • 优先 typedef,确保类型安全
    • 命名规范:类型别名后缀加 _t
  • 内存操作
    • 谨慎使用 offsetof 和 container_of:要确保指针有效
    • 内存对齐:优化结构体成员顺序
  • 跨平台
    • 条件编译:使用宏确保跨平台兼容
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千帐灯无此声

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值