Использование zd против lu для sizeof

Я понимаю, что %zd — это рекомендуемый способ форматирования результата sizeof. Однако я не понимаю, зачем это нужно. Например, использование lu дает мне тот же результат, и в любом случае результат sizeof не является беззнаковым длинным? Например:

printf("Sizeof(char): %lu, Sizeof(short): %lu, Sizeof(int): %lu, Sizeof(long): %lu, Sizeof(long long): %lu, Sizeof(float): %lu, Sizeof(double): %lu, Sizeof(long double): %lu\n"
       ,sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long), sizeof(float), sizeof(double), sizeof(long double));
printf("Sizeof(char): %zd, Sizeof(short): %zd, Sizeof(int): %zd, Sizeof(long): %zd, Sizeof(long long): %zd, Sizeof(float): %zd, Sizeof(double): %zd, Sizeof(long double): %zd"
       ,sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long), sizeof(float), sizeof(double), sizeof(long double));

Sizeof(char): 1, Sizeof(short): 2, Sizeof(int): 4, Sizeof(long): 8, Sizeof(long long): 8, Sizeof(float): 4, Sizeof(double): 8, Sizeof(long double): 16
Sizeof(char): 1, Sizeof(short): 2, Sizeof(int): 4, Sizeof(long): 8, Sizeof(long long): 8, Sizeof(float ): 4, Sizeof(двойной): 8, Sizeof(длинный двойной): 16

Какова причина или преимущество использования %zd и почему это было добавлено в первую очередь?


person carl.hiass    schedule 10.01.2021    source источник
comment
Результатом sizeof является size_t, который может совпадать или не совпадать с unsigned long, в зависимости от используемого компилятора, ОС и процессора. И спецификатором формата является %zu, так как size_t не имеет знака.   -  person user3386109    schedule 10.01.2021
comment
Я хочу сказать потому что Microsoft... (но на самом деле они, вероятно, не единственные).   -  person Siguza    schedule 10.01.2021
comment
@user3386109 user3386109 Понятно, size_t что-то вроде typedef size_t int или typedef size_t <something-else> в зависимости от платформы?   -  person carl.hiass    schedule 10.01.2021
comment
@carl.hiass Да, это общая идея, хотя это может быть встроенный тип, а не typedef.   -  person user3386109    schedule 10.01.2021
comment
Проверьте этот ответ.   -  person Amal K    schedule 10.01.2021
comment
Отвечает ли это на ваш вопрос? Как использовать спецификатор zd с `printf()`?   -  person Ayxan Haqverdili    schedule 10.01.2021
comment
@Siguza long почти никогда не бывает size_t в большинстве встроенных систем.   -  person phuclv    schedule 10.01.2021
comment
Если size_t, unsigned long и unsigned int все имеют 32-битный размер (а они могут быть), не имеет значения, используете ли вы %zu, %lu или %u, но код не переносим. Вот почему вам нужно использовать правильный спецификатор, чтобы printf() знал размер передаваемого аргумента. Все, что у него есть, это promise от спецификатора формата, и он должен верить, что вызывающий объект передал операнд правильного размера. У него нет другого способа узнать, и программист должен сопоставить формат с типом.   -  person Weather Vane    schedule 10.01.2021


Ответы (2)


в любом случае, результат sizeof не является unsigned long?

Нет, он возвращает size_t, а size_t не обязательно должен быть того же размера, что и unsigned long.

Например, в мире Windows unsigned long соответствует 32 битам, а size_t — 64 битам.

Я понимаю, что %zd — это рекомендуемый способ форматирования результата sizeof.

Не совсем.

Используйте %zu для size_t (или %zX, %zx или %zo)
Используйте %zd для ssize_t

Поскольку sizeof возвращает size_t, вам нужно %zu.

person ikegami    schedule 10.01.2021
comment
Есть ли ssize_t в стандартном C? cppreference говорит, что %zd для подписанного size_t, и я не уверен, что это значит. - person Ayxan Haqverdili; 10.01.2021
comment
Этот ответ проливает некоторый свет на этот вопрос, а также упоминает, что ssize_t является POSIX и не обязательно является подписанной версией size_t. Поэтому говорить, что %zd для ssize_t, неверно. - person Ayxan Haqverdili; 10.01.2021
comment
@Ayxan Haqverdili, Re Есть ли ssize_t в стандарте C?, я не говорил, что есть. /// Re здесь также упоминается, что ssize_t не обязательно является подписанной версией size_t. На самом деле это говорит об обратном. Это указывает на то, что, хотя спецификация POSIX явно не говорит, что тип является совпадением, это понимается. - person ikegami; 10.01.2021
comment
Конечно, на практике ssize_t — это size_t со знаком, но ptrdiff_t и %zd, вероятно, будут нормально работать с любым целым числом со знаком, имеющим тот же размер, что и size_t. Я хотел упомянуть, какие гарантии существуют в каких стандартах в случае заинтересованности ОП. - person Ayxan Haqverdili; 10.01.2021
comment
@ikegami В обосновании POSIX говорится, что он должен быть подписанным аналогом size_t. Формулировка такова, что реализация может либо использовать более длинный тип, либо просто использовать подписанную версию типа, лежащего в основе size_t. pubs.opengroup.org/onlinepubs/9699919799/xrat/ - person Keith Thompson; 06.05.2021

Значение, возвращаемое оператором sizeof, имеет тип size_t.

Из стандарта C (6.5.3.4 Операторы sizeof и alignof)

5 Значение результата обоих операторов определяется реализацией, а его тип (целочисленный тип без знака) — size_t, определенный в ‹stddef.h› (и других заголовках).

Тип size_t — это целочисленный тип без знака, определенный реализацией. Обычно он определяется как псевдоним для типа unsigned long, хотя стандарт C этого не требует. В частности, Стандарт допускает, что ранг типа size_t может быть больше, чем ранг типа unsigned long.

Из стандарта C (7.19 Общие определения ‹stddef.h›)

4 Типы, используемые для size_t и ptrdiff_t, не должны иметь целочисленный ранг преобразования выше, чем у signed long int, если только реализация не поддерживает объекты, достаточно большие, чтобы сделать это необходимым.

Поэтому для вывода значений типа size_t следует использовать спецификатор преобразования zu.

person Vlad from Moscow    schedule 10.01.2021