Использование ptrdiff_t - PullRequest
       19

Использование ptrdiff_t

4 голосов
/ 26 марта 2019

Я реализую итератор через непрерывный кусок памяти и пришел к вопросу о его соответствующем использовании. Моя текущая реализация (при условии, что я перебираю массив char s).

typedef struct iterator{
    void *next_ptr;
    void *limit; //one past last element pointer
} iterator_t;

void *next(iterator_t *iterator_ptr){
    void *limit = iterator_ptr -> limit;
    void *next_ptr = iterator_ptr -> next_ptr;
    ptrdiff_t diff = limit - next_ptr;
    if(diff <= 0){
        return NULL;
    }
    iterator_ptr -> next_ptr = ((char *) next_ptr) + 1;
    return next_ptr;
}

Проблема заключается в стандартных претензиях на 6.5.6(p9), которые:

Когда вычтены два указателя, оба должны указывать на элементы тот же объект массива, или один за последним элементом массива объект

Это правда. Я предполагаю, что область, через которую я итерирую, является массивом.

Если результат не может быть представлен в объекте этого тип, поведение не определено. Другими словами, если выражения указывают, соответственно, на i -й и j -й элементы объект массива, выражение (P)-(Q) имеет значение i−j значение вписывается в объект типа ptrdiff_t.

Пределы ptrdiff_t определены в 7.20.3(p2):

пределы ptrdiff_t

PTRDIFF_MIN −65535

PTRDIFF_MAX + 65535

Нет никаких гарантий, что все значения, представленные size_t, должны быть представлены ptrdiff_t.

То есть мы, судя по пределам, можем соответственно вычитать указатели массива максимум из 65535 элементов? Так что это не будет работать в общем случае, когда я хочу вычесть два указателя на элементы массива неизвестного размера?

Ответы [ 2 ]

4 голосов
/ 26 марта 2019

Из спецификации (раздел 7.20.3)

Его значение, определяемое реализацией, должно быть равным или больше по величине (абсолютное значение)чем соответствующее значение, указанное ниже

[Выделить мины]

Таким образом, упомянутые значения являются только минимальными значениями.Реализация может иметь большие ограничения.Я ожидал бы, что ptrdiff_t будет длиной слова целевой платформы (то есть 64-битного типа 64-битных систем).

И обратите внимание, что size_t является без знака целочисленный тип, в то время как ptrdiff_t является знаковым целочисленным типом.Этот тип подразумевает, что не все значения size_t могут быть представлены ptrdiff_t.

3 голосов
/ 26 марта 2019

Это, похоже, проблема в самом стандарте C.

Как вы заметили, 6.5.6 Аддитивные операторы , пункт 9 , в частности, гласит:

Когда вычитаются два указателя, оба должны указывать на элементы одного и того же объекта массива или один за последним элементом последнего объекта массива;Результатом является разница индексов двух элементов массива.Размер результата определяется реализацией, а его тип (целочисленный тип со знаком) ptrdiff_t определен в заголовке <stddef.h>. Если результат не может быть представлен в объекте этого типа, поведение не определено. Другими словами, если выражения P и Q указывают соответственно на i -й иj -й элемент массива, выражение (P)-(Q) имеет значение i-j , если значение соответствует объекту типа ptrdiff_t....

В стандарте C, как представляется, нет гарантии того, что вы можете представить разницу двух указателей в ptrdiff_t.

Реально это будет означать, чтоptrdiff_t должно быть больше size_t.size_t должен покрывать величину только в фиксированном количестве бит.ptrdiff_t должно охватывать как величину, так и направление.Если sizeof( size_t ) == sizeof( ptrdiff_t ), то нет гарантии, что неопределенное поведение в 6.5.6p9 не будет вызвано.

...