为什么我们不能在 C# 中进行 IntPtr 和 UIntPtr 算术?

发布于 2024-10-31 06:23:36 字数 561 浏览 1 评论 0原文

这是一个看似简单的问题:

鉴于本机大小的整数最适合算术,为什么 C#(或任何其他 .NET 语言)不支持使用本机大小的 IntPtrUIntPtr

理想情况下,您可以编写如下代码:

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

这样它就可以在 32 位和 64 位平台上运行。 (目前,您必须使用long。)


编辑:

没有使用它们作为指针(甚至没有提到“指针”这个词)!它们可以被视为 MSIL 中的 native int 和 C 的 stdint.h 中的 intptr_t 的 C# 对应项——它们是整数,<强>不是指针。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

谈场末日恋爱 2024-11-07 06:23:36

在 .NET 4 中,IntPtr 类型的左侧操作数与整数类型(intlong 等)的右侧操作数之间的算术支持。

[编辑]:
正如其他人所说,它们被设计为表示本机语言中的指针(如名称 IntPtr 所暗示的那样)。可以声称您将它们用作本机整数而不是指针,但您不能忽视整数的本机大小重要的主要原因之一是用作指针。如果您正在执行数学运算或其他独立于代码运行所在的处理器和内存架构的通用函数,那么使用 int 和 < code>long ,无论硬件如何,您都知道每种情况下它们的固定大小以及上限和下限。

正如 IntPtr 类型被设计为表示本机指针一样,算术运算也被设计为表示您将在指针上执行的逻辑数学运算:向本机指针添加一些整数偏移量以达到新的值本机指针(并不是不支持添加两个 IntPtr,也不支持使用 IntPtr 作为右侧操作数)。

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).

谈下烟灰 2024-11-07 06:23:36

也许本机大小的整数可以实现最快的算术,但它们肯定不能实现最无错误的程序。

就我个人而言,我讨厌使用整数类型进行编程,当我坐下来开始打字时,我不知道其大小(我正在看着你,C++),而且我绝对更喜欢 CLR 类型所带来的安心使用针对平台定制的 CPU 指令可能会带来非常值得怀疑且肯定有条件的性能优势。

还要考虑到 JIT 编译器可以针对进程运行的体系结构进行优化,而“常规”编译器则必须生成机器代码而无法访问此信息。因此,JIT 编译器可能会同样快地生成代码,因为它知道更多。

我想我并不是唯一一个这么想的人,所以这可能是有原因的。

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.

仅此而已 2024-11-07 06:23:36

我实际上可以想到 IntPtr(或 UIntPtr)有用的一个原因:访问数组的元素需要本机大小的整数。尽管本机整数永远不会暴露给程序员,但它们在 IL 内部使用。 C# 中的 some_array[index] 之类的内容实际上会编译为 IL 中的 some_array[(int)checked((IntPtr)index)]。我在使用 ILSpy 反汇编我自己的代码后注意到了这一点。 (在我的代码中,index 变量是 64 位的。)为了验证反汇编程序没有犯错误,微软自己的 ILDASM 工具显示了 conv.u 的存在。和我的程序集中的 conv.i 指令。这些指令将整数转换为系统的本机表示形式。我不知道 IL 代码中包含所有这些转换指令对性能有何影响,但希望 JIT 足够聪明,能够优化性能损失;如果没有,下一个最好的办法是允许在不进行转换的情况下操作本机整数(在我看来,这可能是使用本机类型的主要动机)。

目前,F# 语言允许使用 nativeint 及其无符号对应项进行算术。但是,在 F# 中数组只能通过 int 进行索引,这意味着 nativeint 对于索引数组来说不是很有用。

如果它确实让您烦恼,请编写自己的编译器来解除对本机整数使用的限制,创建您自己的语言,用 IL 编写代码,或者在编译后调整 IL。就我个人而言,我认为通过使用本机 int 来挤出额外的性能或节省内存并不是一个好主意。如果您希望代码像手套一样适合系统,那么最好使用支持处理器内在函数的较低级语言。

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.

凡尘雨 2024-11-07 06:23:36

.Net Framework 尽量不引入无法解释的操作。即不存在 DateTime + DateTime,因为不存在 2 个日期之和这样的概念。同样的推理也适用于指针类型 - 没有 2 个指针之和的概念。 IntPtr 存储为平台相关的 int 值这一事实并不重要 - 还有许多其他类型在内部存储为基本值(同样,DateTime 可以表示为 long)。

.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).

放低过去 2024-11-07 06:23:36

因为这不是处理内存寻址的“安全”方式。指针算术可能会导致各种错误和内存寻址问题,而 C# 正是为了避免这些问题而设计的。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文