Имам следното предупреждение в gcc компилация в 32-битова архитектура, но нямам такова предупреждение в 64-битова архитектура

symbol.c: Във функцията 'symbol_FPrint':

symbol.c:1209: warning: format '%ld' expects type 'long int', but argument 3 has type 'SYMBOL'
symbol.c: In function 'symbol_FPrintOtter':
symbol.c:1236: warning: format '%ld' expects type 'long int', but argument 3 has type 'SYMBOL'
symbol.c:1239: warning: format '%ld' expects type 'long int', but argument 3 has type 'SYMBOL'
symbol.c:1243: warning: format '%ld' expects type 'long int', but argument 3 has type 'SYMBOL'
symbol.c:1266: warning: format '%ld' expects type 'long int', but argument 3 has type 'SYMBOL' 

В символ.c

1198 #ifdef CHECK
1199     else {
1200       misc_StartErrorReport();
1201       misc_ErrorReport("\n In symbol_FPrint: Cannot print symbol.\n");
1202       misc_FinishErrorReport();
1203     }
1204 #endif
1205   }
1206   else if (symbol_SignatureExists())
1207     fputs(symbol_Name(Symbol), File);
1208   else
1209     fprintf(File, "%ld", Symbol);
1210 }

И SYMBOL се дефинира като:

typedef size_t SYMBOL

Когато замених '%ld' с '%zu', получих следното предупреждение:

symbol.c: In function 'symbol_FPrint':
symbol.c:1209: warning: ISO C90 does not support the 'z' printf length modifier

Забележка: Оттук е редактирано на 26 март 2010 г. и следният проблем е добавен поради сходството му с гореспоменатия проблем.

Имам следното изявление:

printf("\n\t %4d:%4d:%4d:%4d:%4d:%s:%d", Index, S->info, S->weight,
       Precedence[Index],S->props,S->name, S->length);

Предупреждението, което получавам, докато компилирам в 64-битова архитектура, е:

format ‘%4d’ expects type ‘int’, but argument 5 has type ‘size_t’

ето дефинициите на параметъра:

  NAT    props;
  typedef  unsigned int     NAT;

Как мога да се отърва от това, така че да мога да компилирам без предупреждение в 32 и 64 битова архитектура?

Какво може да бъде неговото решение?


person thetna    schedule 11.03.2010    source източник


Отговори (2)


Използвайте %zu вместо %ld като формат за size_t и тогава ще получите правилно поведение (и без предупреждения) както в 32-битовите, така и в 64-битовите компилации.

Ако по някаква причина не можете да използвате %zu (напр. стар или нестандартен компилатор), тогава можете да направите нещо подобно:

#ifdef __LP64__ // if 64 bit environment
#define FMT_SIZE_T "llu"
#else
#define FMT_SIZE_T "lu"
#endif

След това, когато трябва да използвате printf с нещо от тип size_t, можете да направите това:

printf("(sizeof(void *) = %"FMT_SIZE_T" bytes \n", sizeof(void *));
person Paul R    schedule 11.03.2010
comment
това наистина проработи и за двете, получих още едно ново предупреждение на същата линия. ISO C90 не поддържа 'z' gnu_printf модификатор на дължина. Какви могат да бъдат алтернативите в този случай? - person thetna; 11.03.2010
comment
Или използвайте -std=c99, когато компилирате, или #дефинирайте спецификатор на формат, напр. FMT_SIZE_T което е #дефинирано като %llu на 64-битови и %lu на 32-битови компилации. - person Paul R; 11.03.2010
comment
възможно ли е да се премахне такова предупреждение, без да се разчита на стандарт C99? - person thetna; 20.03.2010
comment
@thetna: да, както казах, можете просто условно да #define свой собствен FMT_SIZE_T, който е напр. %lu за за 32-битови компилации и %llu за 64-битови компилации - person Paul R; 20.03.2010
comment
@pual благодаря за отговора. това отново може да е глупав въпрос, но аз съм начинаещ в C. Тези промени правят ли един пакет съвместим както с архитектурната среда, или трябва да дефинирам специално %lu за 32-битова и 64-битова архитектура? - person thetna; 21.03.2010
comment
@thetna: Ще добавя пример към моя отговор, който, надявам се, трябва да изясни това. - person Paul R; 21.03.2010

Намирам %lu за единствения C89-съвместим (или, gcc-c89-warnings-compliant) формат за size_t, на linux. под glibc, size_t изглежда винаги е long unsigned int, така че %lu е подходящо там.

по-специално открих, че gcc-4.4.3 с -std=c89 -pedantic или -std=c89 -Wall ще предупреди за %llu и %lld. има смисъл, тъй като те очакват long long, тип C99.

трагично е, че няма начин да се отпечата size_t по независим от платформата C89-съвместим начин. в C89 всички printf формати се отнасят до конкретни примитивни типове (long, int и т.н.), но във всички C диалекти size_t зависи от платформата (може да е long или int или нещо друго).

както обикновено, microsoft ви хвърля свой собствен специален гаечен ключ. средата за компилиране на windows е зле модифициран C89: има long long, но не и модификатор printf ll. в windows-land %llu става %I64u и %zu става %Iu.

в крайна сметка използвах следното в кодовата база на моята лаборатория:

#ifdef _WIN32
#define PRIuZ "Iu"
#else
#define PRIuZ "lu"
#endif

използвайте:

printf("%"PRIuZ"\n", sizeof(struct foo));

моделирах името от дефинициите в inttypes.h на C99.

настрана: моята версия на win64 mingw-gcc (4.4.5 20100527 (предварителна версия) [svn/rev.159909 - mingw-w64/oz]), плюс -Wall или -pedantic, винаги предупреждава при отпечатване на size_t . оплаква се, че %I64u и %Iu са нестандартни и че %lu е неправилно. изглежда, че компилаторът правилно се спъва от лудостта на Microsoft. трябваше да използвам -pedantic -Wformat=0, за да не хленчи за %Iu.

person sbrudenell    schedule 31.03.2011