C# 中的 64 位指针算术,检查算术溢出改变行为 [英] 64-bit pointer arithmetic in C#, Check for arithmetic overflow changes behavior

查看:32
本文介绍了C# 中的 64 位指针算术,检查算术溢出改变行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些不安全的 C# 代码,它们在 64 位机器上运行的 byte* 类型的大内存块上执行指针运算.大多数情况下它都能正常工作,但是当事情变大时,我经常会遇到某种损坏,即指针不正确.

I have some unsafe C# code that does pointer arithmetic on large blocks of memory on type byte*, running on a 64-bit machine. It works correctly most of the time but when things get large I often get some kind of corruption where the pointer gets incorrect.

奇怪的是,如果我打开检查算术上溢/下溢",一切正常.我没有收到任何溢出异常.但是由于性能受到很大影响,我需要在没有此选项的情况下运行代码.

The strange thing is that if I turn on "Check for arithmetic overflow/underflow" everything works correctly. I do not get any overflow exceptions. But due to the large performance hit I need to run the code without this option.

是什么导致了这种行为差异?

What could be causing this difference in behavior?

推荐答案

这是一个 C# 编译器错误 (在 Connect 上提交).@Grant 显示 C# 编译器生成的 MSIL 将 uint 操作数解释为有符号的.根据 C# 规范,这是错误的,这是相关部分 (18.5.6):

It's a C# compiler bug (filed on Connect). @Grant has shown that the MSIL generated by the C# compiler interprets the uint operand as signed. That's wrong according to the C# spec, here's the relevant section (18.5.6):

18.5.6 指针算法

在不安全的上下文中,+- 运算符(第 7.8.4 节和第 7.8.5 节)可以应用于除 void*.因此,对于每个指针类型 T*,隐式定义了以下运算符:

In an unsafe context, the + and - operators (§7.8.4 and §7.8.5) can be applied to values of all pointer types except void*. Thus, for every pointer type T*, the following operators are implicitly defined:

T* operator +(T* x, int y);
T* operator +(T* x, uint y);
T* operator +(T* x, long y);
T* operator +(T* x, ulong y);
T* operator +(int x, T* y);
T* operator +(uint x, T* y);
T* operator +(long x, T* y);
T* operator +(ulong x, T* y);
T* operator –(T* x, int y);
T* operator –(T* x, uint y);
T* operator –(T* x, long y);
T* operator –(T* x, ulong y);
long operator –(T* x, T* y);

给定一个指针类型T*的表达式P和一个int类型的表达式Nuintlongulong,表达式 P + NN + P计算 T* 类型的指针值,该值是将 N * sizeof(T) 添加到 P 给定的地址.同样,表达式 P - N 计算 T* 类型的指针值,该值是从给定地址中减去 N * sizeof(T)通过 P.

Given an expression P of a pointer type T* and an expression N of type int, uint, long, or ulong, the expressions P + N and N + P compute the pointer value of type T* that results from adding N * sizeof(T) to the address given by P. Likewise, the expression P - N computes the pointer value of type T* that results from subtracting N * sizeof(T) from the address given by P.

给定两个表达式,PQ,指针类型为 T*,表达式 P – Q 计算 PQ 给出的地址之间的差异,然后将该差异除以 sizeof(T).结果的类型总是long.实际上,P - Q 计算为 ((long)(P) - (long)(Q))/sizeof(T).

Given two expressions, P and Q, of a pointer type T*, the expression P – Q computes the difference between the addresses given by P and Q and then divides that difference by sizeof(T). The type of the result is always long. In effect, P - Q is computed as ((long)(P) - (long)(Q)) / sizeof(T).

如果指针算术运算溢出指针类型的域,结果将以实现定义的方式截断,但不会产生异常.

If a pointer arithmetic operation overflows the domain of the pointer type, the result is truncated in an implementation-defined fashion, but no exceptions are produced.


您可以向指针添加 uint,不会发生隐式转换.并且操作不会溢出指针类型的域.因此不允许截断.


You're allowed to add a uint to a pointer, no implicit conversion takes place. And the operation does not overflow the domain of the pointer type. So truncation is not allowed.

这篇关于C# 中的 64 位指针算术,检查算术溢出改变行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆