Почему мы не можем сделать арифметику IntPtr и UIntPtr в C #? - PullRequest
6 голосов
/ 08 апреля 2011

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

Учитывая, что целые числа нативного размера лучше всего подходят для арифметики, почему 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 и intptr_t в C * stdint.h - целые числа, , а не указатели.

Ответы [ 5 ]

6 голосов
/ 08 апреля 2011

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

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

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

6 голосов
/ 08 апреля 2011

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

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

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

Полагаю, я не одинок в своих мыслях, так что это может считаться причиной.

1 голос
/ 27 мая 2012

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

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

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

0 голосов
/ 08 апреля 2011

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

0 голосов
/ 08 апреля 2011

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

...