Чистый код для печати размера t в C++ (или: ближайший эквивалент c99 %z в C++)
у меня есть код C++, который печатает 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, чтобы устранить ложные предупреждения компилятора, сохраняя при этом хорошие.
какие идеи?
редактировать чтобы уточнить, почему я использую 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);
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 или может что-то еще...
трюк может заключаться в том, чтобы привести его к самому большому интегральному типу на машине, не гарантируя потери в преобразовании, а затем использовать строку формата, связанную с этим известным типом.
на Формат C++ библиотека обеспечивает быструю портативную (и безопасную) реализацию printf
в том числе z
модификатор для size_t
:
#include "format.h"
size_t a = 42;
int main() {
fmt::printf("%zu", a);
}
в дополнение к этому он поддерживает синтаксис строки формата Python-like и захватывает информацию о типе, так что вам не нужно предоставлять ее вручную:
fmt::print("{}", a);
Он был протестирован с основными компиляторами и обеспечивает последовательный выход на разных платформах.
отказ от ответственности: я автор этой библиотеки.