Чистый код для печати размера t в C++ (или: ближайший эквивалент c99 %z в C++)
у меня есть код на C++, который печатает a size_t
:
size_t a;
printf("%lu", a);
Я бы хотел, чтобы это компилировалось без предупреждений на 32 - и 64-разрядных архитектурах.
если бы это был C99, я мог бы использовать printf("%z", a);
. Но AFAICT %z
не существует ни в одном стандартном диалекте C++. Так что вместо этого я должен делать
printf("%lu", (unsigned long) a);
это действительно некрасиво.
если нет возможности для печати size_t
s встроенный в язык, интересно, можно ли написать printf обертка или что-то такое, что будет вставлять соответствующие слепки на size_t
s, чтобы устранить ложные предупреждения компилятора, сохраняя при этом хорошие.
какие идеи?
Edit чтобы уточнить, почему я использую printf: у меня есть относительно большая база кода, которую я очищаю. Он использует обертки printf, чтобы делать такие вещи, как "написать предупреждение, записать его в файл и, возможно, выйти из кода с ошибкой". Возможно, я смогу собрать достаточно C++ - foo, чтобы сделать это с помощью оболочки cout, но я бы предпочел не изменять каждый вызов warn() в программе, чтобы избавиться от некоторых предупреждений компилятора.
8 ответов:
большинство компиляторов имеют свой собственный спецификатор для
size_t
иptrdiff_t
аргументы, например, Visual C++ используют %Iu и %Id соответственно, я думаю, что gcc позволит вам использовать %zu и %zd.вы можете создать макрос:
#if defined(_MSC_VER) || defined(__MINGW32__) //__MINGW32__ should goes before __GNUC__ #define JL_SIZE_T_SPECIFIER "%Iu" #define JL_SSIZE_T_SPECIFIER "%Id" #define JL_PTRDIFF_T_SPECIFIER "%Id" #elif defined(__GNUC__) #define JL_SIZE_T_SPECIFIER "%zu" #define JL_SSIZE_T_SPECIFIER "%zd" #define JL_PTRDIFF_T_SPECIFIER "%zd" #else // TODO figure out which to use. #if NUMBITS == 32 #define JL_SIZE_T_SPECIFIER something_unsigned #define JL_SSIZE_T_SPECIFIER something_signed #define JL_PTRDIFF_T_SPECIFIER something_signed #else #define JL_SIZE_T_SPECIFIER something_bigger_unsigned #define JL_SSIZE_T_SPECIFIER something_bigger_signed #define JL_PTRDIFF_T_SPECIFIER something-bigger_signed #endif #endif
использование:
size_t a; printf(JL_SIZE_T_SPECIFIER, a); printf("The size of a is " JL_SIZE_T_SPECIFIER " bytes", a);
The
printf
формата%zu
будет работать нормально на системы, написанные на C++; нет необходимости, чтобы сделать его более сложным.
в windows и Visual Studio реализация printf
%Iu
работает для меня. видеть msdn
C++11
C++11 импортирует C99 so
std::printf
должен поддерживать C99%zu
формат описателя.C++98
на большинстве платформ,
size_t
иuintptr_t
эквивалентны, в этом случае вы можете использоватьPRIuPTR
макрос определен в<cinttypes>
:size_t a = 42; printf("If the answer is %" PRIuPTR " then what is the question?\n", a);
если вы действительно хотите быть в безопасности, литые
uintmax_t
и использоватьPRIuMAX
:printf("If the answer is %" PRIuMAX " then what is the question?\n", static_cast<uintmax_t>(a));
так как вы используете C++, почему бы не использовать IOStreams? Это должно компилироваться без предупреждений и делать правильные вещи с учетом типа, если вы не используете реализацию C++ с мертвым мозгом, которая не определяет
operator <<
наsize_t
.когда фактический выход должен быть сделан с
printf()
, вы все еще можете объединить его с IOStreams, чтобы получить типобезопасное поведение:size_t foo = bar; ostringstream os; os << foo; printf("%s", os.str().c_str());
это не суперэффективно, но ваш случай выше имеет дело с файловым вводом/выводом, так что это ваше узкое место, а не это строка форматирования кода.
вот возможное решение, но оно не совсем красивое..
template< class T > struct GetPrintfID { static const char* id; }; template< class T > const char* GetPrintfID< T >::id = "%u"; template<> struct GetPrintfID< unsigned long long > //or whatever the 64bit unsigned is called.. { static const char* id; }; const char* GetPrintfID< unsigned long long >::id = "%lu"; //should be repeated for any type size_t can ever have printf( GetPrintfID< size_t >::id, sizeof( x ) );
эффективный тип, лежащий в основе size_t-это зависит от реализации. Стандарт C определяет его как тип, возвращаемый оператором sizeof; помимо того, что он является беззнаковым и своего рода целочисленным типом, size_t может быть практически любым размером, который может вместить самое большое значение, которое, как ожидается, будет возвращено sizeof().
следовательно, строка формата, которая будет использоваться для size_t, может варьироваться в зависимости от сервера. Он всегда должен иметь "u", но может быть l или d или может что-то еще...
трюк может заключаться в том, чтобы привести его к самому большому интегральному типу на машине, гарантируя отсутствие потерь в преобразовании, а затем использовать строку формата, связанную с этим известным типом.
The Формат C++ библиотека обеспечивает быструю портативную (и безопасную) реализацию
printf
в том числеz
модификатор дляsize_t
:#include "format.h" size_t a = 42; int main() { fmt::printf("%zu", a); }
в дополнение к этому он поддерживает синтаксис строки формата Python-like и захватывает информацию о типе, так что вам не нужно предоставлять ее вручную:
fmt::print("{}", a);
Он был протестирован с основными компиляторами и обеспечивает последовательный выход на разных платформах.
отказ от ответственности: я автор этой библиотеки.