Какие компиляторы C имеют недопустимые значения вычитания указателя? - PullRequest
2 голосов
/ 24 апреля 2009

Итак, как я узнал из комментариев Майкла Берра к этому ответу , стандарт C не поддерживает целочисленное вычитание из указателей после первого элемента в массиве (который Я полагаю, включает в себя любую выделенную память).

Из раздела 6.5.6 комбинированные C99 + TC1 + TC2 (pdf):

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

Мне нравится арифметика указателей, но я никогда не беспокоился об этом раньше. Я всегда предполагал, что с учетом:

 int a[1];
 int * b = a - 3;
 int * c = b + 3;

Это c == a.

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

Итак, мой вопрос, насколько это распространено? Существуют ли широко используемые компиляторы, которые не делают для меня такой доброты? Является ли правильная арифметика указателей за пределами массива стандартом де-факто?

Ответы [ 4 ]

7 голосов
/ 24 апреля 2009

MSDOS FAR-указатели имели подобные проблемы, которые обычно покрывались «умным» использованием перекрытия регистров сегмента с регистром смещения в реальном режиме. Эффект был в том, что 16-битный сегмент был смещен влево на 4 бита и добавлен к 16-битному смещению, которое давало 20-битный физический адрес, который мог адресовать 1 МБ, что было достаточно, потому что все знали, что никому не понадобится целых 640 КБ ОЗУ. ; -)

В защищенном режиме регистр сегмента фактически был индексом в таблице дескрипторов памяти. Типичная среда выполнения, расширяющая DOS, обычно организует вещи так, что многие сегменты могут обрабатываться так же, как в реальном режиме, что облегчает перенос кода из реального режима. Но у него были некоторые недостатки. Прежде всего, сегмент до выделения не был частью выделения, и поэтому его дескриптор может быть даже недействительным.

На 80286 в защищенном режиме простая загрузка регистра сегмента со значением, которое приведет к загрузке недопустимого дескриптора, вызовет исключение, независимо от того, был ли дескриптор фактически использован для ссылки на память.

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

4 голосов
/ 24 апреля 2009

Это не «реализация, определенная» Стандартом, это «неопределенная» Стандартом. Это означает, что вы не можете рассчитывать на компилятор, поддерживающий его, вы не можете сказать: «ну, этот код безопасен для компилятора X» Вызывая неопределенное поведение, ваша программа не определена.

Практический ответ не в том, «как (где, когда, на каком компиляторе) мне это сойдет с рук»; практический ответ: «Не делай этого».

1 голос
/ 07 ноября 2009

Другая причина заключается в том, что существуют необязательные консервативные сборщики мусора (такие как GC boehm-weiser), которые предполагают, что указатель всегда находится внутри выделенного диапазона, и если нет, им разрешено освобождать память в любое время.

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

0 голосов
/ 25 апреля 2009

ZETA-C для TI Explorer; указатели реализованы в виде массивов и индексов или смещенных массивов, IIRC, поэтому ваш пример, вероятно, не сработает. Начните с zcprim>pointer-subtract в zcprim.lisp, чтобы выяснить, каково будет поведение. Не знаю, было ли это правильно в соответствии со стандартом, но у меня сложилось впечатление, что это так.

...