首页/文档/内存与安全

内存与安全

进阶:指针、切片、检查与契约。

本页讲的是把 CK 计算交给其他程序使用时,如何共享内存。刚开始学习变量、函数和循环时可以先跳过。此处的“宿主程序”指负责调用 CK 的 C 程序或其他运行环境。

指针与切片#

ptr<T>(指针)指向一块内存中的位置。slice<T>(切片)则把这类位置和一个长度放在一起,方便表示“从这里开始的一段数据”。切片不拥有这块内存,也不会复制数据。

下面是一个函数片段,展示如何读取切片中的第一个元素:

export fn first(items: slice<i32>) -> i32 {
  return items[0];
}

调用方必须保证内存确实存在、长度没有超出实际数据、对齐方式正确,并且在 CK 使用期间一直有效。slice(data, len) 只会创建这份“位置加长度”的说明,并不会替你创建或检查内存。

可选的运行时检查#

Native 和 C 输出可以通过命令行选项检查整数溢出和切片索引边界:

ckc build app.ck --kind executable --overflow checked --bounds checked --out app

这类检查不会证明任意指针都有效,也不会证明切片描述的长度和真实内存一致。WebAssembly 输出目前只支持默认的 unchecked 模式。选择目标时请看输出方式的说明。

unsafe 函数和调用约定#

unsafe fn(不安全函数)允许作者声明一些必须由调用方保证的条件,例如两段数据不能重叠。编译器会信任这些条件;如果条件不成立,计算结果可能不可靠。每次调用不安全函数时,都必须把调用写在 unsafe { ... } 块中。

下面是不安全函数的定义片段,并没有包含一个可独立运行的 main 程序:

export unsafe fn saxpy(x: slice<f64>, y: slice<f64>, n: u32) -> void
contract {
  requires n <= x.len && n <= y.len;
  requires noalias(x, y);
  requires aligned(x.data, 32);
  effects read(x), write(y);
}
{
}

此例声明了长度、数据不重叠及内存对齐要求。contract(契约)描述调用前必须满足什么条件,以及函数会读写哪些数据。只有当调用方能保证这些条件时,才能调用该函数。--sanitize-contracts 可以帮助调试 Native 的 run 或可执行程序;普通模式会信任契约。

和 C 等程序配合#

ABI(应用二进制接口)是程序之间约定如何传递参数、返回值和数据布局的规则。CK 的 C、Native 和 WebAssembly 输出有各自的 ABI 细节。涉及指针、切片或 unsafe 函数时,应先阅读相应的完整语言规则和 ABI 文档。

链接到仓库的完整参考文档以 main 分支为准,可能包含尚未进入最新下载版本的功能。

↵ 打开 · esc 关闭