必须用 fixed 锁定托管数组才能用指针操作,否则 gc 移动对象会导致崩溃;编译报“unsafe code not allowed”因未启用不安全代码支持,需在.csproj中添加true或勾选项目属性中的“允许不安全代码”。

不能直接用指针操作托管数组,必须先用 fixed 锁定内存位置,否则 GC 可能移动对象导致指针失效或崩溃。
为什么编译报错“unsafe code not allowed”
这是项目未启用不安全代码支持的典型表现。C# 默认禁用指针操作,必须显式开启:
- 在
.csproj文件中添加<allowunsafeblocks>true</allowunsafeblocks> - 使用 Visual Studio 时:右键项目 → “属性” → “生成”选项卡 → 勾选“允许不安全代码”
- 命令行编译需加
/unsafe参数,例如:csc /unsafe Program.cs - 缺少任一环节都会触发 CS0227 错误
如何安全地对数组用指针读写
托管数组(如 byte[])在堆上分配,GC 可能在任意时刻压缩或移动它。直接取地址(&arr[0])是危险且非法的,必须用 fixed 语句临时固定:
unsafe {
byte[] src = new byte[] { 1, 2, 3, 4 };
byte[] dst = new byte[4];
fixed (byte* ps = src) // 锁定 src,ps 指向首字节
fixed (byte* pd = dst) // 锁定 dst
{
for (int i = 0; i <p>注意:<code>fixed</code> 块外的指针立即失效;多个 <code>fixed</code> 可嵌套但不能跨作用域传递指针变量。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2795" title="C#"><img
src="https://img.php.cn/upload/skill/000/000/081/178936933912641.jpg" alt="C#" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill2795" title="C#" class="overflowclass">C#</a>
<p class="overflowclass">"避开 C# 常见错误——空陷阱、异步陷阱、LINQ 陷阱及资源泄漏。"</p>
</div>
<a rel="nofollow" href="/xiazai/skill2795" title="C#" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><h3>
<code>unsafe</code> 方法 vs <code>unsafe</code> 块的区别</h3><p>二者语法等效,但作用范围和可维护性差异明显:</p>
-
unsafe static void Copy(byte* src, byte* dst, int len):整个方法体都在不安全上下文中,参数本身已是裸指针,适合高频调用、已知内存稳定的场景 -
unsafe { ... }:仅包裹局部逻辑,外围仍是安全代码,适合临时加速一小段计算(如图像像素处理) - 若方法内只有一两行需指针,优先用
unsafe块——避免把整个方法暴露在不可验证风险中 - 函数签名含指针参数(如
int*)的方法,调用方必须也在unsafe上下文中,否则编译失败
常见崩溃原因:忘了 fixed 或越界访问
最典型的运行时问题不是编译错误,而是静默内存破坏或 AccessViolationException:
- 对未
fixed的数组取地址,例如:byte* p = &arr[0]→ 编译器会拒绝,但若用Marshal.UnsafeAddrOfPinnedArrayElement绕过,则极可能在 GC 后指向无效地址 - 指针算术越界,比如循环中用
p[i]但i >= length→ 不触发 .NET 边界检查,直接读写随机内存 - 把指针保存到字段或静态变量中,离开
fixed块后仍尝试解引用 → 未定义行为,大概率 crash - 用
stackalloc分配栈内存时超过 1MB(默认限制),会抛StackOverflowException
指针操作没有“差不多能跑就行”的余地——错一个字节,就可能让整个进程挂掉。调试时优先确认内存是否被正确锁定、长度是否严格校验、指针生命周期是否完全受限在作用域内。









