fixed语句必须在unsafe上下文中使用,且只能固定已声明的数组或字符串变量;不可嵌套固定同一数组,string固定后为UTF-16且不自动null终止,指针离开fixed块即失效。
fixed语句只能用于不安全上下文中
不加
修饰,编译器直接报错
。这不是警告,是硬性限制——哪怕你只写了一行
,整个方法或类型都得显式标记为
。
常见做法是把涉及指针操作的逻辑单独抽出成
方法,而不是给整个类加
前缀。比如:
别忘了项目文件(.csproj)里还得启用不安全代码:
,否则编译通不过。
fixed只能固定“托管堆上可寻址”的变量
的作用是让 GC 在该语句块执行期间不移动数组或字符串的内存位置,但它不能固定任意表达式。以下写法全都会编译失败:
—— 临时数组没赋值给变量,生命周期不可控
——
返回新数组,但没绑定到变量,GC 立刻可能回收
—— 同样,中间对象无引用,fixed 失效
正确姿势只有一条:必须传入一个已声明、且生命周期明确的数组或字符串变量,例如:
fixed 不能嵌套固定同一数组的多个指针
下面这段代码看似合理,实则危险:
因为每次
都会重新 pin 一次,而 GC 可能在两次 pin 之间移动数组(虽然概率低,但标准不保证一致)。更糟的是,某些运行时(如 .NET Core 3.1+)在 debug 模式下会故意让第二次 pin 返回不同地址来暴露这类 bug。
C知道
CSDN推出的一款AI技术问答工具
下载
正确做法是复用同一个指针:
string 固定时要注意 null 终止和编码
对
使用
得到的是 UTF-16 编码的
,不是 C 风格的 null-terminated 字符串。如果你要传给 native API(比如 Windows API 的
),它本身接受宽字符且以 \0 结尾,那没问题;但若目标是 ANSI 或 UTF-8 接口,直接传
会出乱码。
常见误用:
—— 强转不改变编码,只是 reinterpret,结果不可预测
假设
固定后自动带 \0 结尾 —— 实际上 .NET string 不保证末尾有额外 \0,除非你手动加
需要 C 字符串时,应显式转换并确保 null 终止:
最易被忽略的一点:fixed 语句块退出后,指针立即失效,哪怕你把它存进字段或返回出去,后续解引用就是未定义行为——它不会 crash,但可能读到旧数据、新数据,甚至触发 AV。别试图“延长” fixed 的生命周期。
unsafeCS0214: Pointers and fixed size buffers may only be used in an unsafe contextfixedunsafeunsafeunsafeunsafe void ProcessBytes(byte[] data) {
fixed (byte* ptr = data) {
// 操作 ptr
}
}true fixedfixed (int* p = new int[10])fixed (char* p = str.ToCharArray())ToCharArray()fixed (byte* p = buffer.AsSpan().ToArray())byte[] bytes = Encoding.UTF8.GetBytes("hello");
fixed (byte* ptr = bytes) { /* 安全 */ }fixed (byte* p1 = data)
fixed (byte* p2 = data) {
// p1 和 p2 可能指向不同地址!
}fixedfixed (byte* p = data) {
byte* p1 = p;
byte* p2 = p + 4;
// 所有指针都基于 p 偏移
}stringfixedchar*LPCWSTRchar*fixed (char* p = str) { SomeAnsiApi((sbyte*)p); }stringvar utf8Bytes = Encoding.UTF8.GetBytes(str + '\0');
fixed (byte* p = utf8Bytes) { /* 传给 expects_utf8_cstr() */ }