跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

c#如何使用fixed语句_c#fixed语句的正确用法与注意事项

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

相关文章