Спецификаторы формата Typedefs и printf

общее использование typedefs заключается в том, чтобы " тип " переменной передавал лучшее представление о цели переменной без переопределения структуры хранения за ней.

однако я также вижу typedefs как способ изменить структуру хранения для класса переменных за один раз.

например, если я определяю

typedef uint32_t my_offset_t

и имеют переменные типа my_offset_t, переключение кодовой базы с uint32_t to char или uint64_t так же просто, как изменения и перекомпиляции (если я использую sizeof вместо жестко закодированных размеров),за исключением случая printf / scanf.

есть ли способ поменять формат-спецификаторы в соответствии с типом каким-то простым способом, без функций обертки вокруг printf/scanf, если-elses, или ifdefs?

спасибо!

для тех, кто заинтересован, я изменяю LKM, который использовал 16-битные смещения для работы с 32-битными смещениями, но хочу, чтобы он мог идти для 64-бит (или что-то еще!) смещения, при необходимости, с минимальными изменениями.

3 ответов


это сложный бизнес, но <inttypes.h> из C99 и позже показывает, как это сделать.

для каждого из ваших определенных типов вам нужно предоставить себе соответствующий набор макросов " PRI " и "SCN", стараясь избегать стандартизированного пространства имен.

например, вы можете использовать XYZ в качестве префикса проекта и производить:

XYZ_PRIx_my_offset_t
XYZ_PRId_my_offset_t
XYZ_PRIX_my_offset_t
XYZ_PRIu_my_offset_t
XYZ_PRIo_my_offset_t

и эквиваленты SCN. Кроме того, вы бы определили их в терминах эквивалентных макросов для базового типа, Итак:

#define XYZ_PRIx_my_offset_t PRIx32
#define XYZ_PRId_my_offset_t PRId32
#define XYZ_PRIX_my_offset_t PRIX32
#define XYZ_PRIu_my_offset_t PRIu32
#define XYZ_PRIo_my_offset_t PRIo32

в вашем коде вы создаете строки формата, используя XYZ_PRIx_my_offset_t макросы:

printf("Offset: 0x%.8" XYZ_PRIX_my_offset_t "\n", my_offset_value);

если впоследствии вам нужно изменить все на 64-бит, вы соответствующим образом отредактируете typedef и определения макросов, а остальная часть кода останется "неизменной". Если вы действительно осторожны, вы можете получить довольно близко к совершенно неизменным.

убедитесь, что вы компилируете как 32-разрядные, так и 64-разрядные системы с множеством предупреждений. GCC не будет предупреждать о не-проблемы на вашей текущей платформе, но они могут появиться на другой. (Я только что исправил некоторый код, который был чистым на 64-битном, но нечистым для 32-битного; теперь он использует макрос, такой как XYZ_PRId_int4 вместо %d и компилирует чисто на обоих.)


Если вы посмотрите на мои более ранний вопрос о inttypes.h вы можете увидеть, как системные спецификаторы формата могут использоваться совместно с typedefs (через #define), чтобы сделать пользовательские спецификаторы печати для пользовательских типов.


другое решение-конвертировать в и из intmax_t для знаковых типов и uintmax_t для беззнаковых типов. Например:

printf("%ju\n", (uintmax_t)n);

будет работать правильно, если n - это любой тип unsigned.

на *scanf() функции, вам нужно будет прочитать во временный объект, а затем назначить.

(предполагается, что библиотека среды выполнения поддерживает эти функции.)