Спецификаторы формата 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()
функции, вам нужно будет прочитать во временный объект, а затем назначить.
(предполагается, что библиотека среды выполнения поддерживает эти функции.)