% ld преобразование формата для переносимости

У меня есть база кода, которая предназначена для компиляции без предупреждений и запуска без сбоев на нескольких архитектурах, все x86: MSDOS, режим консоли Windows 32, режим Windows 32 GUI, Linux 32 и Linux 64.

До добавления поддержки Linux 64 это было легко. Почти все данные были объявлены как int или из typedefs для BYTE, WORD и DWORD:

typedef unsigned char   BYTE;
typedef unsigned short  WORD;
typedef unsigned long   DWORD;

После добавления 64-битной поддержки gcc DWORD потребовалась небольшая настройка, чтобы остаться как 32-битное значение, так как оно представляло сохраненные данные:

// to compile DWORDs as 32 bits on 64-bit machines:
#if __x86_64__
typedef unsigned int    DWORD;
#else
typedef unsigned long   DWORD;
#endif

И это хорошо работало во всех средах:

DWORD   data;
printf ("%lu", data);

Тем не мение, gcc -Wall Теперь жалуется на преобразование формата:

warning: format ‘%ld’ expects argument of type ‘long int’, but argument
1 has type ‘DWORD {aka unsigned int}’ [-Wformat]

Из-за обширного форматирования, которое делает этот код — тысячи строк форматирования вывода — я бы предпочел не модифицировать форматировщик конкретного типа. Похожий вопрос был ответил с помощью z модификатор:

printf ("%zu", data);

Но это заставляет Turbo C на MSDOS и консоли Win32 делать что-то странное: он показывает спецификацию преобразования %zu в качестве вывода вместо преобразования чего-либо.

Есть ли более чистый способ обработки изменчивости типа таким образом, который соответствует структуре printf и основным типам данных?

4

Решение

Я думаю, что ваш наименее плохой доступный вариант — это взять концептуально <inttypes.h>:

#ifdef _LP64
#define PRIdword  "d"#define PRIudword "u"#else
#define PRIdword  "ld"#define PRIudword "lu"#endif

а потом

DWORD data;
printf("%"PRIdword, data);

Это использует конкатенацию строковых констант, которую должны поддерживать все C90-совместимые компиляторы. Обратите внимание, что правильный макрос для тестирования _LP64не __x86_64__; таким образом, это будет просто работать, когда вы переходите на другую систему LP64 или в новый блестящий режим «x32» в Linux / x86-64 (32-битные указатели, широкие регистры).

Возможно, неплохо было бы инвестировать в оптовую конверсию в <stdint.h> типы, но это не вытащит вас из такого рода вещей, вы бы просто писать

int32_t data;
printf("%"PRId32, data);

вместо этого, и, насколько я знаю, большинство компиляторов Windows еще не иметь <inttypes.h>вздох.

Если вам интересно, то % не находится внутри макроса, поэтому вы можете установить регуляторы формата, если хотите:

printf("%-32"PRIdword, data);
3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector