У меня есть следующее предупреждение при компиляции 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' 

В символе.с

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 }

И СИМВОЛ определяется как:

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 при компиляции, либо #define спецификатор формата, например. 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) для 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). или что-то другое).

как обычно, Майкрософт предлагает вам свой специальный разводной ключ. среда компиляции Windows представляет собой сильно модифицированный C89: он имеет long long, но не имеет модификатора ll printf. в стране окон %llu становится %I64u, а %zu становится %Iu.

в итоге я использовал следующее в кодовой базе моей лаборатории:

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

использовать:

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

я смоделировал имя из определений в C99 inttypes.h.

в стороне: моя версия 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