Why can't we do IntPtr and UIntPtr arithmetic in C#?

纵然是瞬间 提交于 2019-12-22 05:21:52

问题


It's a simple-looking question:

Given that native-sized integers are the best for arithmetic, why doesn't C# (or any other .NET language) support arithmetic with the native-sized IntPtr and UIntPtr?

Ideally, you'd be able to write code like:

for (IntPtr i = 1; i < arr.Length; i += 2) //arr.Length should also return IntPtr
{
    arr[i - 1] += arr[i]; //something random like this
}

so that it would work on both 32-bit and 64-bit platforms. (Currently, you have to use long.)


Edit:

I'm not using these as pointers (the word "pointer" wasn't even mentioned)! They can be just treated as the C# counterpart of native int in MSIL and of intptr_t in C's stdint.h -- which are integers, not pointers.


回答1:


In .NET 4, arithmetic between a left hand operand of type IntPtr and a right hand operand of integer types (int, long, etc) is supported.

[Edit]: As other people have said, they are designed to represent pointers in native languages (as implied by the name IntPtr). It's fine to claim you're using them as native integers rather than pointers, but you can't overlook that one of the primary reasons the native size of an integer ever matters is for use as a pointer. If you're performing mathematical operations, or other general functions that are independent from the processor and memory architecture that your code is running on, it is arguably more useful and intuitive to use types such as int and long where you know their fixed size and upper and lower bounds in every situation regardless of hardware.

Just as the type IntPtr is designed to represent a native pointer, the arithmetic operations are designed to represent logical mathematical operations that you would perform on a pointer: adding some integer offset to a native pointer to reach a new native pointer (not that adding two IntPtrs is not supported, and nor is using IntPtr as the right hand operand).




回答2:


Maybe native-sized integers make for the fastest arithmetic, but they certainly don't make for the most error-free programs.

Personally I hate programming with integer types whose sizes I do not know when I sit down to start typing (I 'm looking at you, C++), and I definitely prefer the peace of mind the CLR types give you over the very doubtful and certainly conditional performance benefit that using CPU instructions tailored to the platform might offer.

Consider also that the JIT compiler can optimize for the architecture the process is running on, in contrast to a "regular" compiler which has to generate machine code without having access to this information. The JIT compiler might therefore generate code just as fast because it knows more.

I imagine I 'm not alone in thinking this, so it might count for a reason.




回答3:


I can actually think of one reason why an IntPtr (or UIntPtr) would be useful: accessing elements of an array requires native-sized integers. Though native integers are never exposed to the programmer, they are internally used in IL. Something like some_array[index] in C# will actually compile down to some_array[(int)checked((IntPtr)index)] in IL. I noticed this after disassembling my own code with ILSpy. (The index variable is 64-bit in my code.) To verify that the disassembler wasn't making a mistake, Microsoft's own ILDASM tool shows the existence of conv.u and conv.i instructions within my assembly. Those instructions convert integers to the system's native representation. I don't know what the performance implication is having all these conversion instructions in the IL code, but hopefully the JIT is smart enough to optimize the performance penalty away; if not, the next best thing is to allow manipulating native integers without conversions (which, in my opinion, might be the main motivation to use a native type).

Currently, the F# language allows the use of nativeint and and its unsigned counterpart for arithmetic. However, arrays can only be indexed by int in F# which means nativeint is not very useful for the purposes of indexing arrays.

If it really bothers you that much, write your own compiler that lifts restrictions on native integer use, create your own language, write your code in IL, or tweak the IL after compiling. Personally, I think it's a bad idea to squeeze out extra performance or save memory by using native int. If you wanted your code to fit the system like a glove, you'd best be using a lower level language with support for processor intrinsics.




回答4:


.Net Framework tries not to introduce operations that can't be explained. I.e. there is no DateTime + DateTime because there is no such concept as sum of 2 dates. The same reasoning applies to pointer types - there is no concept of sum of 2 pointers. The fact that IntPtr is stored as platform depenedent int value does not really matter - there are a lot of other types that internally stored as basic values (again DateTime can be represented as long).




回答5:


Because that's not a "safe" way of handling memory addressing. Pointer arithmetic can lead to all sorts of bugs and memory addressing problems that C# is designed explicitly to avoid.



来源:https://stackoverflow.com/questions/5589846/why-cant-we-do-intptr-and-uintptr-arithmetic-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!