Какой спецификатор следует использовать для печати макроконстанты BUFSIZ с использованием printf в C (C89)

Используем ли мы lu и unsigned long приведение, как в:

printf("%lu\n", (unsigned long)BUFSIZ); /* 512 */

и надеяться на лучшее? или есть другой способ?

И это не дубликат: Как можно переносимо распечатать переменную size_t, используя семейство printf? просто потому, что я не знаю, что такое BUFSIZ тип.


person Bite Bytes    schedule 31.05.2017    source источник
comment
Возможный дубликат Как можно печатать переменную size_t переносимо, используя семейство printf?   -  person Antti Haapala    schedule 31.05.2017
comment
вы можете использовать его, а затем воспользуйтесь советом size_t из дубликата: /   -  person Antti Haapala    schedule 31.05.2017
comment
@AnttiHaapala серьезно? как я могу узнать, что BUFSIZ относится к типу size_t, если @Felix Palmen не дал мне ответа? Мой вопрос не в том, как печатать size_t, а в BUFSIZ, который я даже не знаю, что это за тип.   -  person Bite Bytes    schedule 31.05.2017
comment
это размер a, который, как вы можете предположить, можно преобразовать как size_t без потери информации.   -  person Antti Haapala    schedule 31.05.2017
comment
@BiteBytes Я предположил в своем ответе, потому что size_t - рациональный выбор для него ...   -  person    schedule 31.05.2017
comment
Вы даже не показали BUFSIZ. Если это макрос с неквалифицированным целочисленным значением, то он имеет тип int.   -  person Weather Vane    schedule 31.05.2017
comment
@WeatherVane, библиотека C определяет его, но, поскольку это размер, я бы рассматривал его как _1 _...   -  person    schedule 31.05.2017
comment
@FelixPalmen интересно, MSVC действительно определяет BUFSIZ как 512.   -  person Weather Vane    schedule 31.05.2017


Ответы (3)


Я предполагаю, что BUFSIZ всегда является значением, подходящим для size_t, и других гарантий нет.

В таком случае: Да, это наиболее правильный способ сделать это, если вы ограничены c89. Отсутствие модификатора длины формата, подходящего для size_t, является одним из многих недостатков этого очень старого стандарта. На практике, если вы используете 64-битную систему с LLP64 моделью данных (то есть Win64), size_t действительно больше, чем long, и этот код может работать с большими размерами. Спасибо EOF за подсказку. Все еще на практике: вероятно, его следует определить разумно, и размер буфера ввода-вывода 4G или больше не кажется разумным, поэтому действительно вряд ли вызовет проблемы. с подходом «приведение к unsigned long».

Дополнительное примечание: может быть веская причина для использования этой конструкции даже с компилятором в c99 или c11, и это переносимость на платформу Windows. msvcrt от Microsoft (среда выполнения и стандартная библиотека C) не поддерживает модификатор длины z.

person Community    schedule 31.05.2017
comment
Совершенно уверен в 64-битных окнах sizeof(size_t) > sizeof(unsigned long). - person EOF; 31.05.2017
comment
О, я думаю, ты прав. И тогда вы обречены, потому что ll тоже не работает ... - person ; 31.05.2017
comment
В вопросе указано, что BUFSIZ используется как макроконстанта, поэтому ее нельзя объявлять с типом size_t. Если программист, которому нужно напечатать эту константу, также может свободно ее переопределить, ваше решение кажется разумным. Но если он существует в каком-то унаследованном коде или в чем-то еще, и его неразумно изменять (возможно, он используется во всевозможных странных областях), тогда это не будет иметь значения. - person ely; 31.05.2017
comment
Компилятор Microsoft не позволяет указывать стандарт, так что в любом случае это не вариант. - person Bite Bytes; 31.05.2017
comment
Последние версии Felix MSVC действительно поддерживают спецификацию формата %zu. - person Weather Vane; 31.05.2017
comment
@WeatherVane не в последний раз проверял несколько дней назад на windows 10. - person ; 31.05.2017
comment
Это версия для Windows, а не версия для компилятора? Я использую Windows 7 с MSVC 2015, забив Windows 10. - person Weather Vane; 31.05.2017

Согласно стандарту C (7.21 Ввод / вывод)

SETBUF

который расширяется до целочисленного постоянного выражения, которое является размером буфера, используемого функцией setbuf;

Не уточняется, какой тип константы.

С другой стороны, стандартная функция setvbuf может использоваться для указания буфера, предоставляемого пользователем, или буфера, выделенного функцией. Он имеет следующее объявление

int setvbuf(FILE * restrict stream,
char * restrict buf,
int mode, size_t size);

где параметр size типа size_t указывает размер буфера.

Поскольку размер не может быть отрицательным числом, вы можете вывести его значение как имеющее тип size_t.

person Vlad from Moscow    schedule 31.05.2017
comment
Может ли размер быть отрицательным, не имеет значения. Кроме того, тип параметра для setvbuf() также не имеет особого значения, поскольку аргумент любого другого целочисленного типа будет автоматически преобразован в size_t, при условии, что доступен прототип для setvbuf(), поэтому BUFSIZE может быть другим целочисленным типом. В этом случае передать его printf() проблематично, потому что printf() - это varargs. - person EOF; 31.05.2017
comment
@EOF Ты сам себе противоречишь. Если вы скажете, что отрицательный размер не имеет значения, тогда что будет с размером, когда он будет преобразован в size_t? Так что это ваш комментарий неуместен и неверен. - person Vlad from Moscow; 31.05.2017
comment
Нет. Вы просто не понимаете, в чем проблема. Если вы хотите понять это, я бы рекомендовал прочитать черновик стандарта C11 n1570 о 6.5.2.2 Function calls, особенно о тонкостях преобразования аргументов в отношении функций varargs. - person EOF; 31.05.2017
comment
@EOF Подумайте, как отрицательное значение будет преобразовано в size_t. И подумайте, какой тип параметра size у функции setvbuf, задающей размер буфера. И подумайте также о том, каков тип значения, возвращаемого, например, оператором sizeof для массива символов, который передается функции в качестве аргумента. Так что ваш комментарий не имеет смысла. Это не имеет отношения к моему ответу. - person Vlad from Moscow; 31.05.2017
comment
Как я уже сказал, отрицательные значения не имеют значения. Это действительно просто: 1. Сделайте BUFSIZ типом T1. 2. Вызов setvbuf() с BUFSIZ как size. Здесь, поскольку у setvbuf() есть прототип, T1 будет автоматически преобразован в size_t. 3. Позвоните printf() с помощью BUFSIZ. Здесь, поскольку printf() - это varags, T1 не будет преобразовано, поэтому каким бы ни был случайный безумный неопределенный тип T1, вам потребуется правильный спецификатор %-преобразования. Вы этого не сделаете. - person EOF; 31.05.2017
comment
@VladfromMoscow, вы имели в виду BUFSIZ в своем первом блоке кода? - person ; 31.05.2017
comment
@EOF Очень важно, чтобы размер не мог быть отрицательным. Это означает, что нет особого смысла использовать целочисленный тип со знаком для вывода размера. Если размер отрицательный, автоматическое преобразование дает неверное значение. Так что все ваши комментарии не имеют смысла. - person Vlad from Moscow; 31.05.2017
comment
@VladfromMoscow Есть более различные, несовместимые целочисленные типы, чем просто signed и unsigned. - person EOF; 31.05.2017
comment
@FelixPalmen Я привел описание БУФСИЗА из стандарта. А затем я предоставил стандартную функцию, которую можно использовать для установки размера буфера. - person Vlad from Moscow; 31.05.2017
comment
@EOF Я уже писал, что все ваши комментарии не имеют смысла. - person Vlad from Moscow; 31.05.2017
comment
@VladfromMoscow Пишет, что не соответствует действительности. - person EOF; 31.05.2017

Что ж, легко найти доказательство того, что BUFSIZ определенно не всегда относится к типу size_t. Рассмотрим следующий фрагмент test.c:

#include <stdio.h>
BUFSIZ

Скомпилируйте его в Linux и:

% gcc -E test.c|tail -n 2
# 2 "test.c" 2
8192

Таким образом, это определенно не всегда типа size_t. Константа migth имеет тип int, но она также может не быть int, поэтому самым безопасным должно быть предположение, что ее можно преобразовать как size_t, поскольку аргумент для setvbuf также имеет тип size_t.

Затем воспользуйтесь советом Как можно переносимо распечатать переменную size_t с помощью семейства printf?

person Antti Haapala    schedule 31.05.2017
comment
так что это не обязательно size_t, так почему вы продолжаете настаивать на том, что мой вопрос - это дубликат того, как печатать size_t. - person Bite Bytes; 01.06.2017
comment
@BiteBytes это size_t после (size_t)BUFSIZ. И, конечно же, вы не можете распечатать его переносимо без какого-либо приведения, потому что его тип не указан. - person Antti Haapala; 01.06.2017