Ограничение размера создаваемой структуры данных - PullRequest
0 голосов
/ 20 апреля 2019

Мой заголовочный файл

typedef struct vector vector;

vector * vector_create(size_t size);

Файл c:

vector * vector_create(size_t size){
    if(size >= PTRDIFF_MAX)
        return NULL;
    //actual creation logic
}

Мне нужно ограничить размер vector, чтобы он не превышал PTRDIFF_MAXтак как мне нужно вычесть указатели на один элемент вектора из другого.Проблема возникает, когда я хочу проверить это

void test_create_vector_too_large(void){
#if SIZE_MAX >= PTRDIFF_MAX + 1
    list * lst = list_create(((size_t) PTRDIFF_MAX) + 1);
    assert(!lst);
#endif
}

Этот код выдает тонны предупреждений

/home/kjroff/main.c:55:32: warning: integer overflow in preprocessor expression
 #if SIZE_MAX >= PTRDIFF_MAX + 1
                                ^
/home/kjroff/main.c:55:29: warning: the right operand of ">=" changes sign when promoted
 #if SIZE_MAX >= PTRDIFF_MAX + 1

Цель макроса #if состояла в том, чтобы проверить, является ли верхний предел ptrdiff_t превышает верхний предел size_t.Если они одинаковы, этот тест не имеет смысла.Но это так в случае PTRDIFF_MAX < SIZE_MAX.

Как правильно написать такое утверждение?

Ответы [ 2 ]

4 голосов
/ 20 апреля 2019

Сравнение, как правило, бесполезно, поскольку size_t и ptrdiff_t обычно имеют одинаковую ширину, но size_t не подписано, а ptrdiff_t подписано, поэтому SIZE_MAX обязательно больше, чем PTRDIFF_MAX. Это не является строго определенным стандартом C, поскольку size_t является просто типом, используемым для выражений размера, и, несмотря на намерение, явно не указан, чтобы быть достаточным для представления размера любого объекта. Точно так же, ptrdiff_t является просто типом, используемым для различий указателей, и, несмотря на намерение, явно не указан, чтобы быть достаточным для представления различий всех указателей.

Тем не менее, вы можете изменить сравнение на SIZE_MAX > PTRDIFF_MAX, что эквивалентно, как указано pmg . Другой способ уменьшить количество предупреждений - изменить 1 на 1u, получив SIZE_MAX > PTRDIFF_MAX + 1u. Согласно C 2018 6.10.1 4, в предварительной обработке целочисленные типы ведут себя так, как если бы они были intmax_t и uintmax_t, поэтому 1u имеет тип uintmax_t, поэтому PTRDIFF_MAX будет преобразовано в uintmax_t, затем добавляется к 1u (который не будет переполнен), и сравнение будет между двумя uintmax_t типами (избегая предупреждения).

Вопрос гласит: «Мне нужно ограничить размер вектора не более, чем PTRDIFF_MAX, поскольку мне нужно вычесть указатели на один элемент вектора из другого». Но единица size_t составляет один байт, и единица ptrdiff_t - это один элемент массива. Если тип vector не является одним байтом, результат вычитания двух указателей vector * будет уменьшен. Даже в ограниченных системах, где size_t пытается охватить все возможные размеры, в ptrdiff_t должно быть достаточно места для различий двух указателей vector *, независимо от размера базового массива. Так что тест if(size >= PTRDIFF_MAX) кажется бесполезным.

2 голосов
/ 20 апреля 2019

Как правильно написать такое утверждение?

Вместо

#if SIZE_MAX >= PTRDIFF_MAX + 1

Вычитание (SIZE_MAX - не менее 65535), поэтому переполнение невозможно.

#if SIZE_MAX - 1 >= PTRDIFF_MAX

или просто используйте > @ pmg

#if SIZE_MAX > PTRDIFF_MAX
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...