У меня есть база кода, которая предназначена для компиляции без предупреждений и запуска без сбоев на нескольких архитектурах, все 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 и основным типам данных?
Я думаю, что ваш наименее плохой доступный вариант — это взять концептуально <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);
Других решений пока нет …