64位指针运算在C#中,检查运算溢出改变行为 [英] 64-bit pointer arithmetic in C#, Check for arithmetic overflow changes behavior
问题描述
我有一些不安全的C#code,做指针运算,大块内存上键入字节*
,在64位机器上运行。它正常工作的大部分时间,但是当事情变得很大,我经常得到一些腐败现象在指针变得不正确。
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.
但奇怪的是,如果我打开检查算术溢/下溢一切正常。我没有得到任何溢出异常。但由于大型演出打我需要没有这个选项运行code。
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#编译器错误(<一href="https://connect.microsoft.com/VisualStudio/feedback/details/675205/c-compiler-performs-sign-extension-during-unsigned-pointer-arithmetic"相对=nofollow>提交的连接)。 <一href="http://stackoverflow.com/questions/6321650/64-bit-pointer-arithmetic-in-c-check-for-arithmetic-overflow-changes-behavior/6334135#6334135">@Grant显示由C#编译器跨$ P $点的 UINT
操作产生的MSIL的签名。这是不对的,根据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)可以应用于所有指针类型的值,除了无效*
。因此,对于每一个指针类型 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 *
和前pression的前pression P
N
类型 INT
, UINT
,长
或 ULONG
,前pressions 点+ N
和 N + P
计算式的指针值 T *
,从增加的结果 N * sizeof的(T)
由给出的地址P
。同样,前pression p - N
计算式的指针值 T *
,从减去结果 N * sizeof的(T)
从点给出的地址
。
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
.
由于两位前pressions, P
和问:
,指针类型的 T *
,前pression 对 - Q
计算由 P 给出的地址之间的差异code>和
问:
,然后把这种差异由的sizeof(T)
。结果的类型总是长
。实际上,对 - Q
计算为((长)(P) - (长)(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.
这篇关于64位指针运算在C#中,检查运算溢出改变行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!