Почему мы не можем выполнить арифметику IntPtr и UIntPtr в C#?

это простой вопрос:

учитывая, что целые числа собственного размера лучше всего подходят для арифметики, почему C# (или любой другой язык .NET) не поддерживает арифметику с собственным размером IntPtr и UIntPtr?

в идеале вы сможете написать код, например:

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


Edit:

Я не использование это как указатели (слово "указатель" даже не упоминалось)! Их можно просто рассматривать как аналог c#native int в MSIL и of intptr_t В С stdint.h -- которых-целые числа, не указатели.

5 ответов


в .NET 4 арифметика между левым операндом типа IntPtr и правый операнд целочисленных типов (int, long, etc) is поддержал.

[редактирование]: Как говорили другие люди, они предназначены для представления указателей на родных языках (как подразумевается под именем IntPtr). Можно утверждать, что вы используете их как собственные целые числа, а не указатели, но вы не можете упустить из виду, что одна из основных причин собственного размера целого числа когда-либо имеет значение предназначен для использования в качестве указателя. Если вы выполняете математические операции или другие общие функции, не зависящие от процессора и архитектуры памяти, на которой работает ваш код, возможно, более полезно и интуитивно использовать такие типы, как int и long где вы знаете их фиксированный размер и верхние и нижние границы в каждой ситуации независимо от оборудования.

так же, как тип IntPtr предназначен для представления собственного указателя, арифметические операции предназначен для представления логических математических операций, которые вы выполняете с указателем: добавление некоторого целочисленного смещения к собственному указателю для достижения нового собственного указателя (не то, что добавление двух IntPtrs не поддерживается, и не используя IntPtr как правый операнд).


может родного размера целых чисел для быстрый арифметика, но они, конечно, не для самых безошибочных программ.

Лично Мне ненавижу Программирование с целочисленными типами, размеры которых я не знаю, когда я сажусь, чтобы начать печатать (я смотрю на вас, C++), и я определенно предпочитаю спокойствие типы CLR дают вам очень сомнительное и, безусловно, условное преимущество производительности, что с помощью инструкций CPU с учетом платформа может предложить.

учтите также, что JIT-компилятор может оптимизировать архитектуру, на которой выполняется процесс, в отличие от" обычного " компилятора, который должен генерировать машинный код без доступа к этой информации. Поэтому компилятор JIT может генерировать код так же быстро, потому что он знает больше.

Я думаю, что я не одинок в этом, так что это может считаться по какой-то причине.


Я действительно могу придумать одну причину, по которой IntPtr (или UIntPtr) был бы полезен: для доступа к элементам массива требуются целые числа собственного размера. Хотя собственные целые числа никогда не подвергаются программисту, они внутренне используются в IL. Что-то вроде some_array[index] в C# фактически скомпилируется до some_array[(int)checked((IntPtr)index)] in IL. Я заметил это после разборки моей код с ILSpy. (The index переменная 64-бит в моем коде.), Чтобы убедиться, что дизассемблер не ошибиться, Собственный инструмент Microsoft ILDASM показывает существование conv.u и conv.i инструкции в моей сборке. Эти инструкции преобразуют целые числа в собственное представление системы. Я не знаю, что означает производительность, имея все эти инструкции по преобразованию в коде IL, но, надеюсь, JIT достаточно умен, чтобы оптимизировать штраф за производительность; если нет, то лучше всего разрешить манипулировать целыми числами без преобразований (что, на мой взгляд, может быть основным мотивация к использованию родного типа).

в настоящее время, язык F# позволяет использовать nativeint and и его беззнаковый аналог для арифметики. Однако массивы могут быть индексированы только по int в F# что означает nativeint не очень полезно для целей индексирования массивов.

если это действительно беспокоит Вас, напишите свой собственный компилятор, который снимает ограничения на использование собственного целого числа, создайте свой собственный язык, напишите код в IL или настройте IL после компиляции. Лично я думаю, что это плохая идея выжать дополнительную производительность или сохранить память с помощью native int. Если вы хотите, чтобы ваш код соответствовал системе, как перчатка, вам лучше использовать язык более низкого уровня с поддержкой встроенных процессоров.


.Net Framework пытается не вводить операции, которые невозможно объяснить. Т. е. нет DateTime + DateTime, потому что нет такого понятия, как сумма 2 дат. То же самое относится и к типам указателей - нет понятия суммы 2 указателей. Тот факт, что IntPtr хранится как значение платформы depenedent int, на самом деле не имеет значения - есть много других типов, которые внутренне хранятся как базовые значения (опять же DateTime может быть представлен как long).


потому что это не "безопасный" способ обработки адресации памяти. Арифметика указателя может привести ко всевозможным ошибкам и проблемам с памятью, которые C# явно предназначен для предотвращения.