переменные типа size_t и ptrdiff_t

Читая сообщения в Интернете, связанные с size_t и ptrdiff_t, я хочу подтвердить следующее:

  1. если максимальный размер массива меньше 1/2*(max number represent-able by size_t), я могу безопасно использовать ptrdiff_t и проверять относительные расстояния между двумя указателями на один и тот же объект? (Поскольку я говорил о массиве, «указатели на тот же объект» означают «указатели на тот же массив ").

  2. если я хочу объявить переменную, которая может представлять смещение от другого указателя, мне лучше объявить ее как тип ptrdiff_t?

  3. Как вывести переменные типа size_t и ptrdiff_t в C и C ++? Правильно ли следующее: Строка межплатформенного формата для переменных типа size_t?

  4. is uintptr_t - это просто другое имя для size_t ИЛИ его следует использовать как отдельный тип от size_t?

  5. ssize_t и intptr_t другие имена для ptrdiff_t ИЛИ его нужно использовать по-другому?

Я начинаю использовать gcc на Ubuntu. Я только что узнал об этих типах при использовании чужих кодов.

ДОБАВЛЕНО: я хочу использовать отрицательные смещения. А какая разница в использовании uintptr_t и intptr_t?


person Rich    schedule 31.10.2011    source источник
comment
Есть ли опечатки _ptrdiff_t_ и ssize_t?   -  person Mooing Duck    schedule 31.10.2011
comment
@MooingDuck: ssize_t - это тип Posix (например, это тип возврата read и write). _ptrdiff_t_ действительно похоже на опечатку.   -  person Mike Seymour    schedule 31.10.2011
comment
@MooningDuck: для ptrdiff_t я просто пытался, выделено ли оно курсивом. просто удалил _ вокруг слова.   -  person Rich    schedule 31.10.2011
comment
@Mike: В чем разница между типом Posix и обычным типом, созданным на C или C ++? Могу ли я использовать их как взаимозаменяемые?   -  person Rich    schedule 31.10.2011
comment
Мне кажется, что вы повторно задаете кучу вопросов, на которые здесь уже даны ответы, а затем спрашиваете, верны ли ответы. Какие у вас есть основания сомневаться в предыдущих ответах? Какой новый вопрос задается в этом сообщении?   -  person Rob Kennedy    schedule 31.10.2011
comment
@Rich: Posix - это стандарт для Unix-подобных операционных систем, отдельный от языковых стандартов. Более переносимо придерживаться стандартных типов языка, поскольку некоторые платформы не определяют типы Posix.   -  person Mike Seymour    schedule 31.10.2011
comment
@RobKennedy: В других сообщениях содержится информация об этих типах по частям. и иногда они содержат противоречивые ответы. Я собираю эту информацию и хочу прояснить оставшиеся у меня сомнения. И это шанс раз и навсегда разобраться в этих типах. Пожалуйста, извините меня, если вы думаете, что все вопросы для вас тривиальны, но не для меня. Спасибо.   -  person Rich    schedule 31.10.2011
comment
@MikeSeymour: похоже, что у ptrdiff_t есть синоним intptr_t, согласно этой странице: (www.viva64.com/en/a/0050). есть ли разница между uintptr_t и intptr_t, если я хочу использовать их для представления указателей? Почему я спрашиваю, у указателей нет знаков, верно? Разве использование uintptr_t и intptr_t не имело бы такого же эффекта?   -  person Rich    schedule 31.10.2011
comment
@Rich: ptrdiff_t не является синонимом intptr_t согласно языковому стандарту. Они имеют разное предназначение и на некоторых платформах могут иметь разные размеры. Нет никакой разницы между intptr_t и uintptr_t в том, что касается представления указателей; разница в том, как вы хотите использовать целочисленные представления.   -  person Mike Seymour    schedule 31.10.2011
comment
Кстати, будьте осторожны при расчете смещения. В частности, не умножайте беззнаковое значение на -1. Получите абсолютное значение приращения, приведите к ptrdiff_t, а затем отмените его. Это забавно; Я только что исправил ошибку в очень похожем коде. Это так меня раздражало, что я написал об этом в блоге. Тем не менее, моя проблема связана с unsigned int, которая вызвала проблему.   -  person Ed S.    schedule 01.11.2011


Ответы (3)


1: если максимальный размер массива меньше 1/2 * (максимальное число, представимое size_t), я могу безопасно использовать ptrdiff_t и проверять относительные расстояния между двумя указателями на один и тот же объект?

Так будет, если sizeof(size_t) <= sizeof(prtdiff_t). Так будет и в разумной реализации, но нет никаких гарантий.

2: если я хочу объявить переменную, которая может представлять смещение от другого указателя, мне лучше объявить ее как тип ptrdiff_t?

Да, именно для этого и предназначен этот шрифт.

3: Как вывести переменные типа size_t и ptrdiff_t в C и C ++?

In C:

printf("%zu %td\n", size, ptrdiff);

In C++:

std::cout << size << ' ' << ptrdiff << '\n';

4. Является ли uintptr_t просто другим именем для size_t ИЛИ его следует использовать как отдельный тип от size_t?

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

5: ssize_t и intptr_t другое имя для ptrdiff_t ИЛИ его нужно использовать по-другому?

ssize_t не является стандартным типом для языков C или C ++; он определяется Posix как тип некоторых аргументов функции и возвращаемых значений. Лучше всего использовать ptrdiff_t, кроме случаев, когда вы имеете дело непосредственно с функциями Posix.

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

Я действительно хочу использовать отрицательные смещения. А какая разница в использовании uintptr_t и intptr_t?

Не используйте ни один из этих типов для представления смещений; используйте ptrdiff_t. Используйте эти типы в особых случаях, когда по какой-то причине вы хотите преобразовать указатели в их целочисленные представления.

person Mike Seymour    schedule 31.10.2011
comment
+1. Вы можете использовать size_t вместо ptrdiff_t, если вы собираетесь иметь дело только с положительными смещениями от базового указателя (что часто имеет место в моей работе). Если вам могут потребоваться отрицательные смещения, то правильный тип ptrdiff_t. - person Jonathan Leffler; 31.10.2011
comment
ptrdiff_t может отличаться от intptr_t на некоторых платформах; на многих платформах они будут представлены однотипными. - person Jonathan Leffler; 31.10.2011
comment
@MikeSeymour: Я понял, что мои доказательства не имеют ничего общего с типами указателей и больше связаны с ptrdiff_t. Неважно - person Mooing Duck; 31.10.2011
comment
Обратите внимание, что для (2) различия / смещения между указателями определены только для элементов одного и того же массива. Если вы хотите сохранить разницу между произвольными указателями, вы должны преобразовать их в uintptr_t и принять разницу как целые числа. - person R.. GitHub STOP HELPING ICE; 01.11.2011
comment
Как вы решаете, использовать ли intptr_t или uintptr_t, когда вам нужен один из них? - person user541686; 08.01.2013
comment
@Mehrdad: Если вы не выполняете арифметические действия с преобразованным значением, это не имеет значения. Если да, то вы уже покинули царство здравомыслия, но беззнаковая арифметика, вероятно, немного менее безумна. - person Mike Seymour; 09.01.2013
comment
Nitpicking: Нет никакой гарантии, что std::cout << size << ' ' << ptrdiff << '\n'; будет работать, IIRC. size_t не гарантируется, что его можно будет использовать для потоковой передачи. - person L. F.; 08.09.2019

uintptr_t и intptr_t достаточно велики, чтобы хранить любое значение указателя void* без потери информации. Они должны иметь возможность однозначно представлять адрес любого объекта во всем адресном пространстве вашей программы, включая любой байт в любом объекте.

size_t - тип, полученный оператором sizeof; ptrdiff_t - это тип, полученный вычитанием двух указателей. Они должны быть достаточно большими для одного объекта. (А объект может быть настолько большим, что вычитание двух указателей, указывающих на противоположные концы, приведет к переполнению.)

Большинство современных систем имеют единое монолитное адресное пространство, но C разработан для работы с системами, в которых его нет. Например, в некоторых системах самый большой из возможных объектов может составлять небольшую часть размера всего адресного пространства - и сравнение или вычитание указателей на отдельные объекты может быть бессмысленным. (Подумайте о схеме сегментированной адресации, где при вычитании и сравнении указателя учитывается только часть адреса со смещением.)

person Keith Thompson    schedule 31.10.2011

Предполагая, что _ptrdiff_t_ - опечатка:

1) Да. Если максимальный размер массива меньше SIZE_MAX/2, вы можете безопасно использовать ptrdiff_t
2) Иногда: ptrdiff_t - обычно разница между двумя указателями, а size_t - смещение. Здесь важно то, что size_t всегда положительно, ptrdiff_t может быть отрицательным. Обратите внимание, что на некоторых платформах они могут сильно отличаться по размеру.
3) Вы выводите переменные типа size_t и ptrdiff_t так же, как вы выводите переменные любого другого типа.

size_t a = 10;
ptrdiff_t b = 20;
printf("%u %d", ((unsigned int)a), ((int)b));
std::cout << a << b;

4) uintptr_t - целое число без знака размером не менее int*, чтобы безопасно разрешить целочисленную математику для указателей. Насколько я могу судить, size_t не обязательно будет таким же.
5) ssize_t - нестандартный тип C, соответствующий ptrdiff_t. Вместо этого используйте ptrdiff_t. (On platforms supporting the POSIX 1003.1-1996 API standard, which includes most Unix-like systems, a signed variant of size_t named ssize_t is available, which was not part of the ANSI or ISO C standards. http://en.wikipedia.org/wiki/Size_t)

person Mooing Duck    schedule 31.10.2011
comment
Я не думаю, что ssize_t нестандартно для ptrdiff_t. Обычно он используется как счетчик байтов или возврат ошибок из подпрограмм чтения / записи. - person user7116; 31.10.2011
comment
Я знаю платформу, где size_t - 16 бит, а ptrdiff_t - 32 бита. Кроме того, ssize_t является эквивалентом size_t со знаком. Так получилось, что на исходной платформе это был тот же базовый тип, что и для ptrdiff_t. - person Joshua; 31.10.2011
comment
Опасность: ваш printf не работает, если sizeof (size_t) или sizeof (ptrdiff_t) ›sizeof (int) [разрешены оба]. Никогда не передавайте size_t или ptrdiff_t в printf без предварительного преобразования их в базовые типы. - person Joshua; 31.10.2011
comment
Если я хочу использовать смещение, которое может быть как положительным, так и отрицательным, я должен использовать ptrdiff_t? правильный? Я только что отредактировал свои вопросы. Есть ссылка, как выводить эти типы. ссылка. Это правильный формат? - person Rich; 31.10.2011
comment
ssize_t - это тип POSIX; это значение, возвращаемое read() и write() и связанными функциями. - person Jonathan Leffler; 31.10.2011
comment
@sixlettervariables: как говорит Джонатан, ssize_t не является C стандартным типом, это стандартный тип Posix. - person Mooing Duck; 31.10.2011
comment
@Joshua: Я изменил формулировку №2, чтобы было понятнее, что они могут очень сильно отличаться. Принял ваше предложение для printf. - person Mooing Duck; 31.10.2011
comment
@ Богатый: если вам нужны негативы, используйте ptrdiff_t. Да, эта ссылка верна, но я бы порекомендовал то, что меня поправил Джошуа, привести к примитивному типу для безопасности. - person Mooing Duck; 31.10.2011
comment
C99 определяет %zu для печати size_t и %td для печати ptrdiff_t. (Каждый раз, когда вам нужно кастовать, вы, вероятно, делаете что-то не так.) См. Ответ Майка Сеймура. - person Nemo; 31.10.2011