Арифметика указателей и подписанные / неподписанные преобразования! - PullRequest
3 голосов
/ 05 апреля 2010

В случае арифметики с указателями, целые числа автоматически преобразуются в подписанные варианты? Если да, то почему?

Предположим, я делаю

int *pointer; 
int *pointerdiff;
unsigned int uiVal = -1;

pointerdiff = pointer + uiVal // Pointer will contain valid address here.

, где указатель является указателем на int, а uiVal инициализируется значением -1, тогда я обнаружил, что адрес в указателях уменьшается на 4. Почему значение без знака -1 здесь не рассматривается?

Ответы [ 3 ]

8 голосов
/ 05 апреля 2010

Похоже, ваш указатель переполнен.

Давайте посчитаем. Допустим, вы работаете на 32-битной машине, и ваш указатель инициализирован на 0x 12 34 56 78. Затем мы инициализируем переменную типа unsigned в -1, то есть 0x FF FF FF FF. Поскольку целое число без знака, -1 переполнено и фактически представляет 4 294 967 295.

Ваш указатель на целое число (int*), поэтому каждое приращение фактически увеличивает адрес на sizeof int, то есть 4 на стандартном компьютере x86. Таким образом, мы на самом деле добавляем 0x 03 FF FF FF FC (то есть 0x FF FF FF FF * 4).

Теперь давайте сложим два вместе.

  0x 00 12 34 56 78
+ 0x 03 FF FF FF FC
-------------------
  0x 04 12 34 56 74

Конечно, это переполняется, потому что теперь у нас есть 40-битное значение, а указатель 32-битный и может содержать только столько информации. Поэтому мы теряем 04 в начале. В результате получается 0x 12 34 56 74, то есть 0x 12 34 56 78 - 4.

3 голосов
/ 05 апреля 2010

Да, целочисленные операнды повышаются. Но это не имеет значения здесь. uiVal не может быть -1, если это тип без знака. Вероятно, вы сделали

unsigned int uiVal = -1;
pointer + uiVal ...

Но это будет так же, как

pointer + UINT_MAX ...

И это может вызвать неопределенное поведение, если диапазон адресов, который может удерживать указатель, не справляется с этим дополнением. Стандарт говорит в 5.7/4

Для целей этих операторов указатель на объект без массива ведет себя так же, как указатель на первый элемент массива длиной один с типом объекта в качестве типа его элемента.

Когда выражение с целочисленным типом добавляется или вычитается из указателя, результат имеет тип операнда указателя. Если операнд-указатель указывает на элемент объекта массива, и массив достаточно большой, [...]. Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, при оценке не должно быть переполнения; в противном случае , поведение не определено.

То есть, если указатель результата не лежит в том же массиве или за одним концом, или если он делает это, но сделал это из-за переполнения, поведение не определено.

0 голосов
/ 05 апреля 2010

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

...