9

There is this code:

#include <cstdio>
#include <chrono>

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

When this is compiled in 64bit mode, then there is a warning:

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);
                   ^

This warning is not present when compiling in 32bit mode (with -m32 flag). It looks like that std::chrono::duration::rep is of type long int in 64bit programs and long long int in 32bit programs.

Is there a portable way to print it like %zu specifier for size_t?

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
wulujey
  • 384
  • 1
  • 2
  • 9
  • 7
    why not use `std::cout` since you're using C++? It will be portable. – NathanOliver Aug 31 '17 at 11:42
  • This is not an option. :( This is just a simplified example of the problem. – wulujey Aug 31 '17 at 11:44
  • `long long int` instead of auto? naaaah, that's not c++11 enough. Although when using it with printf I would rather go for `int64_t` – Sopel Aug 31 '17 at 11:46
  • 1
    It looks that printf("%" PRId64 "", d); fixes the problem. It seems that this std::chrono::duration::rep is a 64bit number in 32 and 64 bit systems, so just that should be ensured. – wulujey Aug 31 '17 at 11:48
  • Perhaps you might be allowed to use a temporary c++'ism. "std::ostringstream ss; ss << d;" to create a string, then a simple "printf("%s", ss.str().c_str());" Portable, and not using std::cout. – 2785528 Aug 31 '17 at 12:04

7 Answers7

10

As you said that the usage of std::cout is not an option you can cast the value to the smallest needed data type1 here it's long long int2 and use the corresponding conversion specifier:

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

To avoid the explicit cast you can also use the data type directly instead of the auto specifier:

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

1 With smallest needed data type I mean the smallest type that can represent the value in both implementations.
2 The long long int type has to be at least 64 bit wide, see here on SO.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
7

Instead of using the auto qualifier, use a fixed size integer int64_t.

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

int main()
{
    int64_t d = std::chrono::microseconds(1).count();
    printf("%" PRId64 "\n", d);
    return 0;
}
Clonk
  • 2,025
  • 1
  • 11
  • 26
4

I suggest you use std::cout, since you are in C++. This will be portable.


However, if you must use printf, change this:

printf("%lld", d);

to this:

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

Another approach would be to cast d to the highest data type (which can hold both types), like this:

printf("%lld", static_cast<long long int>(d));
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • The OP is asking for something that will work if it is a `long int` or a long long int`. I don't see how `printf("%ld", d);` satisfies that. – NathanOliver Aug 31 '17 at 11:44
  • I've reread the question and now I don't think my suggestion is needed. I was going to suggest converting to a string which will future proof it but the OP seems to only be concerned about 32 and 64 bits, not a possible future 128 but type. – NathanOliver Aug 31 '17 at 11:54
4

You can cast it to long long int before printing:

#include <cstdio>
#include <chrono>

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

But it seems me that it is better to use std::cout

Amadeus
  • 10,199
  • 3
  • 25
  • 31
2

A portable (i.e. C++) approach to consider, that does not use std::cout

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

or perhaps

 {
   printf("%s", std::to_string(d).c_str() );
 }
2785528
  • 5,438
  • 2
  • 18
  • 20
0

To avoid the warning you can cast d to long long int.

printf("%lld", static_cast<long long int> (d));
jumper0x08
  • 131
  • 5
0

Perhaps not directly related to the 32/64 bit problem at hand, but some of us are on embedded systems with odd output consoles and C++ libraries. (Plus we know that if we have to do any serious output formatting, printf is saner than iomanip!)

Anyway, this prints the guts of a duration and may be useful for debugging. Modify to taste.

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
            )
         );
}
PatchyFog
  • 1,551
  • 16
  • 17