Вот этот код:

#include <cstdio>
#include <chrono>

int main()
{
  auto d = std::chrono::microseconds(1).count();
  printf("%lld", d);
  return 0;
}

Когда это скомпилировано в 64-битном режиме, появляется предупреждение:

main.cpp: In function ‘int main()’:
main.cpp:7:19: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘long int’ [-Wformat=]
   printf("%lld", d);
                   ^

Это предупреждение отсутствует при компиляции в 32-битном режиме (с флагом -m32). Похоже, что std::chrono::duration::rep имеет тип long int в 64-битных программах и long long int в 32-битных программах.

Есть ли портативный способ напечатать его как %zu спецификатор для size_t?

8
wulujey 31 Авг 2017 в 14:40

7 ответов

Лучший ответ

Вместо использования квалификатора auto используйте целое число фиксированного размера int64_t.

#include <cstdio>
#include <chrono>
#include <cinttypes>

int main()
{
    int64_t d = std::chrono::microseconds(1).count();
    printf("%" PRId64 "\n", d);
    return 0;
}
5
Clonk 31 Авг 2017 в 11:48

Переносимый (т. Е. C ++) подход к рассмотрению, который не использует std :: cout

 {
   // create a string:
   std::ostringstream ss; 
   ss << d;" 
   // then
   printf("%s", ss.str().c_str());
 } 

Или возможно

 {
   printf("%s", std::to_string(d).c_str() );
 }
2
2785528 31 Авг 2017 в 12:07

Как вы сказали, использование std::cout не вариант Вы можете привести значение к наименьшему необходимому типу данных 1 , здесь оно long long int 2 и использовать соответствующий спецификатор преобразования:

printf("%lld", static_cast<long long int>(d));

Чтобы избежать явного приведения, вы также можете напрямую использовать тип данных вместо автоматического спецификатора :

long long int d = std::chrono::microseconds(1).count();
printf("%lld", d);

1 Под наименьшим необходимым типом данных я подразумеваю наименьший тип, который может представлять значение в обеих реализациях.
2 Тип long long int должен иметь ширину не менее 64 бит,
см. здесь на SO .

9
Andre Kampling 13 Сен 2017 в 09:04

Возможно, это не связано напрямую с проблемой 32/64 бит, но некоторые из нас работают на встроенных системах с нечетными выходными консолями и библиотеками C ++. (Кроме того, мы знаем, что если нам нужно выполнить какое-либо серьезное форматирование вывода, printf более разумен, чем iomanip!)

В любом случае, это печатает кишки продолжительности и может быть полезно для отладки. Модифицировать по вкусу.

template<typename Rep, typename Ratio>
printf_dur( std::chrono::duration< Rep, Ratio > dur )
{
    printf( "%lld ticks of %lld/%lld == %.3fs",
            (long long int) dur.count(),
            (long long int) Ratio::num,
            (long long int) Ratio::den,
            ( (Ratio::num == 1LL)
              ? (float) dur.count() / (float) Ratio::den
              : (float) dur.count() * (float) Ratio::num
            )
         );
}
0
PatchyFog 12 Дек 2018 в 13:10

Вы можете привести его к long long int перед печатью:

#include <cstdio>
#include <chrono>

int main()
{
  auto d = std::chrono::microseconds(1).count();
  printf("%lld", static_cast<long long int>(d));
  return 0;
}

Но мне кажется, что лучше использовать std::cout

4
Amadeus 31 Авг 2017 в 11:45

Я предлагаю вам использовать std::cout, поскольку вы находитесь на C ++. Это будет портативный.


Однако, если вы должны использовать printf, измените это:

printf("%lld", d);

К этому:

#include <cinttypes>
printf("%" PRId64 "", d); 

Другой подход заключается в приведении d к наивысшему типу данных (который может содержать оба типа), например так:

printf("%lld", static_cast<long long int>(d));
4
gsamaras 31 Авг 2017 в 12:08

Чтобы избежать предупреждения, вы можете привести d к long long int.

printf("%lld", static_cast<long long int> (d));
0
jumper0x08 31 Авг 2017 в 12:00