|
| 1 | +# `<stddef.h>` |
| 2 | + |
| 3 | +**<stddef.h>** 定义了一些跨平台、跨实现的通用类型、宏和常量,几乎所有C程序都会直接或间接用到它们。 |
| 4 | + |
| 5 | +很多其他标准头文件(如`<stdlib.h>`、`<stdio.h>`、`<string.h>`等)都会隐式包含`<stddef.h>`,所以你经常不需要手动包含它。但当你直接使用其中的类型或宏时,最好显式包含,以提高代码可读性和可移植性。 |
| 6 | + |
| 7 | +## 如何使用 |
| 8 | + |
| 9 | +```c |
| 10 | +#include <stddef.h> |
| 11 | +``` |
| 12 | + |
| 13 | +## 1. size_t —— 表示对象大小的无符号整数类型 |
| 14 | + |
| 15 | +- **定义目的**:`sizeof` 操作符的返回类型,也是很多函数(如`malloc`、`strlen`)用来表示大小或长度的参数类型。 |
| 16 | +- **特点**:无符号整数,能表示任何对象可能的最大大小。 |
| 17 | +- **典型实现**:通常是 `unsigned long long`。 |
| 18 | +- **示例**: |
| 19 | + |
| 20 | + ```c |
| 21 | + #include <stddef.h> |
| 22 | + #include <stdio.h> |
| 23 | + |
| 24 | + int main() { |
| 25 | + size_t size = sizeof(int); // 获取 int 类型占多少字节 |
| 26 | + printf("int 的大小是:%zu 字节\n", size); // 注意:打印 size_t 用 %zu |
| 27 | + return 0; |
| 28 | + } |
| 29 | + ``` |
| 30 | +
|
| 31 | + 可能的输出: |
| 32 | +
|
| 33 | + <TerminalWindow title="zsh - test_sizeof"> |
| 34 | +
|
| 35 | + int 的大小是:4 字节 |
| 36 | +
|
| 37 | + </TerminalWindow> |
| 38 | +
|
| 39 | +- **小贴士**:永远不要用 `int` 或 `unsigned int` 来代替`size_t`,这样能保证代码在不同平台上的可移植性。 |
| 40 | +
|
| 41 | +## 2. ptrdiff_t —— 指针相减结果的带符号整数类型 |
| 42 | +
|
| 43 | +- **定义目的**:两个指针相减的结果类型(例如数组中元素之间的距离)。 |
| 44 | +- **特点**:带符号整数,能表示同一数组内任意两个指针的差值(包括负值)。 |
| 45 | +- **典型实现**:通常是 `long` 或 `long long` 的有符号版本。 |
| 46 | +- **示例**: |
| 47 | +
|
| 48 | + ```c |
| 49 | + #include <stddef.h> |
| 50 | + #include <stdio.h> |
| 51 | +
|
| 52 | + int main() { |
| 53 | + int arr[] = {10, 20, 30, 40}; |
| 54 | + int *p1 = &arr[0]; |
| 55 | + int *p2 = &arr[3]; |
| 56 | + ptrdiff_t diff = p2 - p1; // 结果可能是 3 |
| 57 | + printf("指针差:%td\n", diff); // 打印 ptrdiff_t 用 %td |
| 58 | + return 0; |
| 59 | + } |
| 60 | + ``` |
| 61 | + |
| 62 | + 可能的输出: |
| 63 | + |
| 64 | + <TerminalWindow title="zsh - test_ptrdiff"> |
| 65 | + |
| 66 | + 指针差:3 |
| 67 | + |
| 68 | + </TerminalWindow> |
| 69 | + |
| 70 | +- **小贴士**:在循环遍历数组时,常用 `ptrdiff_t` 作为索引差来避免溢出问题。 |
| 71 | + |
| 72 | +## 3. wchar_t —— 宽字符类型 |
| 73 | + |
| 74 | +- **定义目的**:用于表示宽字符(wide character),支持更大的字符集(如Unicode)。 |
| 75 | +- **特点**:整数类型,足够大到能容纳任何支持的宽字符编码。 |
| 76 | +- **示例**: |
| 77 | + |
| 78 | + ```c |
| 79 | + #include <stddef.h> |
| 80 | + #include <wchar.h> // 宽字符函数通常在这里 |
| 81 | + |
| 82 | + int main() { |
| 83 | + wchar_t wc = L'中'; // 宽字符字面量用 L 前缀 |
| 84 | + return 0; |
| 85 | + } |
| 86 | + ``` |
| 87 | +
|
| 88 | +## 4. max_align_t —— 最大对齐要求的标量类型(C11及以后引入) |
| 89 | +
|
| 90 | +- **定义目的**:一个对象类型,它的対齐要求是所有标量类型中最大的。 |
| 91 | +- **用途**:在动态分配内存时,确保内存能满足最严格的对齐需求(比如用在 `aligned_alloc` 或自定义内存池)。 |
| 92 | +- **示例**: |
| 93 | +
|
| 94 | + ```c |
| 95 | + #include <stddef.h> |
| 96 | + #include <stdlib.h> |
| 97 | +
|
| 98 | + int main() { |
| 99 | + void *p = aligned_alloc(alignof(max_align_t), sizeof(max_align_t) * 10); |
| 100 | + // 分配的内存能满足最严格的对齐 |
| 101 | + free(p); |
| 102 | + return 0; |
| 103 | + } |
| 104 | + ``` |
| 105 | + |
| 106 | +- 这个功能在编写需要严格对齐的代码(如操作系统内核或嵌入式)时特别有用。 |
| 107 | + |
| 108 | +## 5. NULL —— 空指针常量 |
| 109 | + |
| 110 | +- **定义**:通常是`((void*)0)` 或 `0`。 |
| 111 | +- **用途**:表示指针不指向任何有效对象。 |
| 112 | +- **示例**: |
| 113 | + |
| 114 | + ```c |
| 115 | + #include <stddef.h> |
| 116 | + |
| 117 | + int main() { |
| 118 | + int *p = NULL; // 安全初始化指针 |
| 119 | + if (p == NULL) { |
| 120 | + // 指针为空 |
| 121 | + } |
| 122 | + return 0; |
| 123 | + } |
| 124 | + ``` |
| 125 | +
|
| 126 | +- 注:C23 引入了 `nullptr`,在初始化指针的时候推荐写 `nulllptr`。 |
| 127 | +
|
| 128 | +## 6. offsetof —— 计算结构体成员偏移的宏 |
| 129 | +
|
| 130 | +- **定义**:`offsetof(type, member)` 返回成员`member`相对于结构体`type`起始地址的字节偏移量。 |
| 131 | +- **特点**:结果类型是`size_t`。 |
| 132 | +- **示例**: |
| 133 | +
|
| 134 | + ```c |
| 135 | + #include <stddef.h> |
| 136 | + #include <stdio.h> |
| 137 | +
|
| 138 | + struct Student { |
| 139 | + int id; |
| 140 | + char name[20]; |
| 141 | + double score; |
| 142 | + }; |
| 143 | +
|
| 144 | + int main() { |
| 145 | + size_t offset = offsetof(struct Student, score); |
| 146 | + printf("score 成员的偏移量:%zu 字节\n", offset); |
| 147 | + return 0; |
| 148 | + } |
| 149 | + ``` |
| 150 | + |
| 151 | + 可能的输出: |
| 152 | + |
| 153 | + <TerminalWindow title="zsh - test_offsetof"> |
| 154 | + |
| 155 | + score 成员的偏移量:24 字节 |
| 156 | + |
| 157 | + </TerminalWindow> |
| 158 | + |
| 159 | +- **小贴士**:常用于调试、序列化、内存布局分析等场景。注意:不能用于有柔性数组成员或位域的复杂情况。 |
| 160 | + |
| 161 | +## 总结 |
| 162 | + |
| 163 | +`<stddef.h>` 虽然内容不多,但它是C语言的“基石”之一——它提供的类型和宏保证了代码的**可移植性**和**安全性**。在实际编程中: |
| 164 | + |
| 165 | +- 几乎所有涉及大小、指针、内存布局的代码都会用到它。 |
| 166 | +- 建议在需要这些类型时显式 `#include <stddef.h>`。 |
| 167 | +- 配合其他头文件(如 `<stdint.h>` 提供固定宽度整数,`<stdalign.h>` 提供对齐宏)使用,能写出更健壮的代码。 |
0 commit comments