Подтвердить что ты не робот

C99 printf formatters vs С++ 11 пользовательских литералов

Этот код:

#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc,char **argv)
{
   uint64_t val=1234567890;
   printf("%"PRId64"\n",val);
   exit(0);
}

Работает для C99, С++ 03, С++ 11 в соответствии с GCC 4.5, но не работает на С++ 11 в соответствии с GCC 4.7.1. Добавление пробела до PRId64 позволяет GCC 4.7.1 скомпилировать его.

Какой из них правильный?

4b9b3361

Ответ 1

gcc 4.7.1 является правильным. Согласно стандарту,

2.2 Фазы перевода [lex.phases]

1 - приоритет среди синтаксических правил перевода определяется следующим фазы. [...]
3. Исходный файл разбивается на токены предварительной обработки (2.5) и последовательности символов пробела (включая комментарии). [...]
4. Выполняются предпроцессорные директивы, макро-вызовы расширяются, [...]

И за 2,5 токены препроцессора [lex.pptoken], определяемый пользователем-string-literal - это маркерная обработка предварительной обработки:

2.14.8 Определенные пользователем литералы [lex.ext]

пользователя де определенно строка литерал:
  string-literal ud-suffix
уд-суффикс:
  Идентификатор

Таким образом, макрораспределение фазы PRId64 не имеет значения, так как "%"PRId64 уже анализируется как один токен предварительной обработки, заданный пользователем, - строковый литерал "%" и ud-suffix PRId64.

О, это будет потрясающе; каждый должен будет изменить

printf("%"PRId64"\n", val);

к

printf("%" PRId64"\n", val);     // note extra space

Однако! gcc и clang согласились обрабатывать пользовательские строковые литералы без основного подчеркивания в суффиксе в виде двух отдельных токенов (по критерию неравномерности), см. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52538, поэтому для будущих версий gcc (я думаю, 4,8 ветка) существующий код снова будет работать.