1

Тема: Різниця між uinptr_t, size_t, ptrdiff_t

У чому різниця між uinptr_t, size_t, ptrdiff_t?
Я от прочитав, що тип size_t - це беззнаковий тип і що в нього можна помістити вказівник, але навіщо тоді є тип uinptr_t?
Яка тоді між ними різниця?

2

Re: Різниця між uinptr_t, size_t, ptrdiff_t

size_t - це беззнаковий тип і що в нього можна помістити вказівник

А чи завжди можна? Якщо, наприклад, використовується модель пам'яті, де вказівник задається як сегмент і зміщення, а розмір об'єкта не може перевищувати максимального розміру сегмента, тоді size_t мав би відповідати розрядності зміщення (без сегмента), і помістити вказівник у нього, в загальному випадку, було б неможливо.

Подякували: koala, leofun012

3

Re: Різниця між uinptr_t, size_t, ptrdiff_t

Це для екзотичних архітектур.
Читаємо стандарт:

7.18.1.4 Integer types capable of holding object pointers написав:

The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
The following type designates an unsigned integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
uintptr_t

7.17 Common definitions <stddef.h> написав:

ptrdiff_t
which is the signed integer type of the result of subtracting two pointers;
size_t
which is the unsigned integer type of the result of the sizeof operator

Для 32-х і 64-бітних x86 та ARM, наскільки я розумію, різниці дійсно немає. Але це не єдині можливі моделі пам'яті. Скажімо, 16-бітні 8086 мали максимальний розмір об'єктів у 65536 байтів, але "далекі" вказівники (FAR) були удвічі більшими, 32 біти (вони розкладалися у два різні регістри, причому вони не просто додавалися, а із зсувом, так що вся пам'ять мала об'єм до 1МБ). Тобто size_t мав бути unsigned short, але uintptr_t вже unsigned long.

Подякували: mimik, P.Y., leofun013

4

Re: Різниця між uinptr_t, size_t, ptrdiff_t

Тобто це таки різні штуки?
І для вказівників краще використовувати uinptr_t

5

Re: Різниця між uinptr_t, size_t, ptrdiff_t

Для вказівників краще використовувати вказівники.

Подякували: 0xDADA11C7, leofun012

6 Востаннє редагувалося wander (16.09.2020 21:35:38)

Re: Різниця між uinptr_t, size_t, ptrdiff_t

mimik написав:

Я от прочитав, що тип size_t - це беззнаковий тип і що в нього можна помістити вказівник
[...]
Тобто це таки різні штуки?

Тип uintptr_t - це і є тип, спеціально призначений для "зберігання" вказівників. Саме в цей тип (а не в size_t) можна безпечно записати вказівник. Для того цей тип і був введений.

Тип size_t - беззнаковий тип, здатний зберігати байтовий розмір найбільшого безперервного об'єкта. Однак з цього ніяк не випливає, що "в змінну типу size_t може бути безпечно поміщений вказівник." Ніхто вам не пообіцяє, що реалізація дозволить вам створювати об'єкти розміром "на всю пам'ять" (на весь адресний простір). Реалізація має право обмежити максимальний розмір об'єкта на свій розсуд і, відповідно, зменшити розмір типу size_t. З цієї причини в тип size_t не можна записати вказівник. Розмір типу size_t в загальному випадку - менше або дорівнює розміру вказівника.

Класичний приклад реалізацій з "маленьким" size_t - платформи з сегментною організацією пам'яті. Твердження, що в тип size_t завжди можна записати вказівник (як за посиланням), як правило робляться через незнання людьми, які не бачили ніяких інших моделей пам'яті, крім плоскої. Не намагайтеся використовувати тип size_t для зберігання вказівників. Для цього існує uintptr_t.

Тип ptrdiff_t - знаковий тип, який призначений для зберігання різниці двох вказівників, що вказують на елементи одного і того ж масиву. З цього випливає, що в загальному випадку тип ptrdiff_t повинен бути на 1 біт ширше, ніж тип size_t. Однак специфікація С++ не вимагає цього і дозволяють типу ptrdiff_t мати ту ж саму ширину, що size_t. Це означає, що якщо ви зумієте створити масив, розміром більше ніж SIZE_MAX / 2, то різниця між покажчиками на елементи такого масиву запросто може не поміститися в ptrdiff_t. Деякі реалізації, в яких ptrdiff_t і size_t мають однакову ширину, просто забороняють створювати об'єкти, розміром більше SIZE_MAX / 2 байт. А деякі - не забороняють і перекладають всю відповідальність на плечі користувача.

Подякували: mimik, P.Y., leofun013