From 27e6d02970a9bb35dcb419ca8fc2b5812c62d05c Mon Sep 17 00:00:00 2001 From: jinzhongjia Date: Wed, 20 Sep 2023 00:18:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8C=87=E9=92=88=E7=AB=A0?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bun.lockb | Bin 36746 -> 36798 bytes learn/basic/advanced_type/pointer.md | 259 +++++++++++++++++++++++- learn/basic/process_control/decision.md | 2 +- learn/basic/process_control/loop.md | 2 +- 4 files changed, 260 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index 11b0752d2f268464eb793adc7a3016d3c4238367..5930907840bd1355bddc8893f8624d59574775c4 100755 GIT binary patch delta 5533 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 UwQ$fQl|^*8#@6yq<-K1229aGth5!Hn diff --git a/learn/basic/advanced_type/pointer.md b/learn/basic/advanced_type/pointer.md index 8d6ca60c..0f69ff40 100644 --- a/learn/basic/advanced_type/pointer.md +++ b/learn/basic/advanced_type/pointer.md @@ -4,4 +4,261 @@ outline: deep # 指针 -TODO +> zig 作为一门 low level 语言,那肯定要有指针的。 + +指针是指向一块内存区域地址的变量,它存储了一个地址,我们可以通过指针来操作其指向内存区域。 + +**取地址**:通过 `&` 符号来获取某个变量所对应的内存地址,如 `&integer` 就是获取变量 `integer` 的内存地址。 + +zig 的指针和 C 的指针略有不同,包含两种指针,一种单项(single-item)指针,一种是多项(many-item)指针,它们的解引用的方式也略有不同。 + +:::warning 关于指针运算 + +zig 本身支持指针运算,但有一点需要注意:最好将指针分配给 `[*]T` 类型后再进行计算。 + +尤其是在切片中,不可直接对其指针进行更改,这会破坏切片的内部结构! + +::: + +## 单项指针 + +单项指针指向单个元素。 + +单项指针的类型为:`*T`,`T`是所指向内存区域的类型,解引用方法是 `ptr.*`。 + +:::details 示例 + +```zig +const print = @import("std").debug.print; + +pub fn main() !void { + var integer: i16 = 666; + const ptr = &integer; + ptr.* = ptr.* + 1; + + print("{}\n", .{integer}); +} +``` + +::: + +## 多项指针 + +多项指针指向位置数量的多个元素。 + +多项指针的类型为:`[*]T`,`T`是所指向内存区域的类型,且该类型必须具有明确的大小(这意味着它不能是 [`anyopaque`](https://ziglang.org/documentation/0.11.0/#toc-C-Type-Primitives) 和其他任意[不透明类型](https://ziglang.org/documentation/0.11.0/#opaque))。 + +解引用方法支持以下几种: + +- 索引语法 `ptr[i]` +- 切片语法 `ptr[start..end]` +- 指针运算 `ptr + x`,`ptr - x` + +:::details 示例 + +```zig +const print = @import("std").debug.print; + +pub fn main() !void { + const array = [_]i32{ 1, 2, 3, 4 }; + var ptr: [*]const i32 = &array; + + print("第一个元素:{}\n", .{ptr[0]}); +} +``` + +::: + +:::info 🅿️ 提示 + +对于数组和切片,它们也有对应的指针类型。 + +数组:`*[N]T`,N是数组的长度,它相当于一个指向数组的单项指针。 + +切片:`[]T`,它相当于一个胖指针,包含了一个 指针类型 `[*]T` 和 长度。 + +数组和切片的指针都存储了长度,因此它们除了指针默认的语法外,还有一个额外的语法 `ptr.len`,用来获取它们的长度。 + +:::details 示例 + +```zig +const print = @import("std").debug.print; + +pub fn main() !void { + var array = [_]i32{ 1, 2, 3, 4 }; + var arr_ptr: *const [4]i32 = &array; + + print("数组第一个元素为:{}\n", .{arr_ptr[0]}); + print("数组长度为:{}\n", .{arr_ptr.len}); + + var slice = array[1 .. array.len - 1]; + var slice_ptr: []i32 = slice; + + print("切片第一个元素为:{}\n", .{slice_ptr[0]}); + print("切片长度为:{}\n", .{slice_ptr.len}); +} +``` + +::: + +### 哨兵指针 + +哨兵指针就和哨兵数组类似,我们使用语法 `[*:x]T`,这个指针标记了边界的值,故称为“哨兵”。 + +它的长度有标记值 `x` 来确定,这样做的好处就是提供了针对缓冲区溢出和过度读取的保护。 + +:::details 示例 + +我们接下来演示一个示例,该示例中使用了 zig 可以无缝与 C 交互的特性,故你可以暂时略过这里! + +```zig +const std = @import("std"); + +// 我们也可以用 std.c.printf 代替 +pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; + +pub fn main() anyerror!void { + _ = printf("Hello, world!\n"); // OK +} +``` + +以上代码编译需要额外连接 libc ,你只需要在你的 `build.zig` 中添加 `exe.linkLibC();` 即可。 + +::: + +## 额外特性 + +以下的是指针的额外特性,初学者可以直接略过以下部分,等到你需要时再来学习即可! + +### `volatile` + +> 如果不知道什么是指针操作的“ _副作用_ ”,那么这里你可以略过,等你需要时再来查看! + +对指针的操作应假定为没有副作用。如果存在副作用,例如使用内存映射输入输出(Memory Mapped Input/Output),则需要使用 `volatile` 关键字来修饰。 + +在以下代码中,保证使用 `mmio_ptr` 的值进行操作(这里你看起来可能会感到迷惑,在编译代码时,可以能会对值进行缓存,这里保证每次都使用 `mmio_ptr` 的值,以避免没有触发 “副作用”),并保证了代码执行的顺序。 + +```zig +// 在这里我们使用了单元测试功能 +const expect = @import("std").testing.expect; + +test "volatile" { + const mmio_ptr: *volatile u8 = @ptrFromInt(0x12345678); + try expect(@TypeOf(mmio_ptr) == *volatile u8); +} +``` + +该节内容,仅仅讲述的少量内容,如果要了解更多,你可能需要查看[官方文档](https://ziglang.org/documentation/0.11.0/#toc-volatile)! + +### 对齐 + +> 如果你不知道内存对齐的含义是什么,那么本节内容你可以跳过了,等到你需要时再来查看! + +每种类型都有一个对齐方式——数个字节,这样,当从内存加载或存储该类型的值时,内存地址必须能被该数字整除。我们可以使用 `@alignOf` 找出任何类型的内存对齐大小。 + +内存对齐大小取决于 CPU 架构,但始终是 2 的幂,并且小于 1 << 29。 + +在 Zig 中,指针类型具有对齐值。如果该值等于基础类型的对齐方式,则可以从类型中省略它: + +```zig +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; + +test "variable alignment" { + var x: i32 = 1234; + // 获取内存对齐信息 + const align_of_i32 = @alignOf(@TypeOf(x)); + // 尝试比较类型 + try expect(@TypeOf(&x) == *i32); + // 尝试在设置内存对齐后再进行类型比较 + try expect(*i32 == *align(align_of_i32) i32); + + if (builtin.target.cpu.arch == .x86_64) { + // 获取了 x86_64 架构的指针对齐大小 + try expect(@typeInfo(*i32).Pointer.alignment == 4); + } +} +``` + +:::info 🅿️ 提示 + +和 `*i32` 类型可以强制转换为 `*const i32` 类型类似,具有较大对齐大小的指针可以隐式转换为具有较小对齐大小的指针,但反之则不然。 + +如果有一个指针或切片的对齐方式较小,但知道它实际上具有较大的对齐方式,请使用 `@alignCast` 将指针更改为更对齐的指针,例如:`@as([]align(4) u8, @alignCast(slice4))`,这在运行时无操作,但插入了安全检查。 + +:::details 示例 + +```zig +const expect = @import("std").testing.expect; + +var foo: u8 align(4) = 100; + +test "global variable alignment" { + try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); + try expect(@TypeOf(&foo) == *align(4) u8); + const as_pointer_to_array: *align(4) [1]u8 = &foo; + const as_slice: []align(4) u8 = as_pointer_to_array; + const as_unaligned_slice: []u8 = as_slice; + try expect(as_unaligned_slice[0] == 100); +} + +fn derp() align(@sizeOf(usize) * 2) i32 { + return 1234; +} +fn noop1() align(1) void {} +fn noop4() align(4) void {} + +test "function alignment" { + try expect(derp() == 1234); + try expect(@TypeOf(noop1) == fn () align(1) void); + try expect(@TypeOf(noop4) == fn () align(4) void); + noop1(); + noop4(); +} +``` + +::: + +### 零指针 + +零指针实际上是一个未定义的错误行为([Pointer Cast Invalid Null](https://ziglang.org/documentation/0.11.0/#Pointer-Cast-Invalid-Null)),但是当我们给指针增加上 `allowzero` 修饰符后,它就变成合法的行为了! + +:::warning 关于零指针的使用 + +请只在目标 OS 为 `freestanding` 时使用零指针,如果想表示 `null` 指针,请使用[可选类型](/basic/optional_type)! + +::: + +:::details 示例 + +```zig +const std = @import("std"); +const expect = std.testing.expect; + +test "allowzero" { + var zero: usize = 0; + var ptr: *allowzero i32 = @ptrFromInt(zero); + try expect(@intFromPtr(ptr) == 0); +} +``` + +::: + +### 编译期 + +只要代码不依赖于未定义的内存布局,那么指针也可以在编译期发挥作用! + +```zig +const expect = @import("std").testing.expect; + +test "comptime pointers" { + comptime { + var x: i32 = 1; + const ptr = &x; + ptr.* += 1; + x += 1; + try expect(ptr.* == 3); + } +} +``` diff --git a/learn/basic/process_control/decision.md b/learn/basic/process_control/decision.md index f4f31b3e..ef7579a6 100644 --- a/learn/basic/process_control/decision.md +++ b/learn/basic/process_control/decision.md @@ -4,4 +4,4 @@ outline: deep # 条件 -TODO \ No newline at end of file +TODO diff --git a/learn/basic/process_control/loop.md b/learn/basic/process_control/loop.md index 58d19d66..068fe2ae 100644 --- a/learn/basic/process_control/loop.md +++ b/learn/basic/process_control/loop.md @@ -6,4 +6,4 @@ outline: deep -TODO \ No newline at end of file +TODO