'Is there a way to bypass printf errors on different compilers?

I have the following line of code:

printf("\n\nTime taken for simulation: %ld milliseconds\n", duration.count() );

On my home machine, I get the error,

main.cpp:292:65: error: format specifies type 'long' but the argument has type 'std::__1::chrono::duration<long long, std::__1::ratio<1, 1000>>::rep' (aka 'long long') [-Werror,-Wformat]

This error is sorted out if I change %ld to %lld I use g++ -std=c++14. Home compiler version is:

Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: arm64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

On the linux cluster I operate, if run it with %lld, I get the following error,

main.cpp:229:83: error: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘std::chrono::duration<long int, std::ratio<1, 1000> >::rep {aka long int}’ [-Werror=format=]

I use g++ -std=c++14. Cluster compiler version is:

g++ (GCC) 7.3.1 20180303 (Red Hat 7.3.1-5)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

if I change %lld to %ld, it is all good.

Is there a way I can print out duration.count(), where duration is defined as auto duration = std::chrono::duration_cast<std::chrono::milliseconds> (stop-start); where stop, start are variables of type specified by std::chrono::high_resolution_clock::now();.

Any advice you have would be appreciated.



Solution 1:[1]

A simple solution is to unconditionally convert to long long:

long long count = duration.count();
printf("%lld", count);

On the other hand, I recommend avoiding printf and its footguns.

Solution 2:[2]

(Assuming you need to use printf())

Couple your type definition with a specifier definition:

typedef my_duration_t std::chrono::duration<long long, std::milli>;
#define MY_DURATION_SPECIFIER "%lld"

and then you write:

auto duration = std::chrono::duration_cast<my_duration_t> (stop-start);
printf(
    "\n\nTime taken for simulation: " MY_DURATION_SPECIFIER " milliseconds\n",
    duration.count() 
);

this (ugly) approach is the one used in stdint.h for the size-specific integer specifiers:

printf("Easy as " PRId64 "!\n", ((int64_t) 123));

see also here.

Solution 3:[3]

There are format macros for many types if you #include <cinttypes>, but it appears std::chrono::duration doesn't have a macro.

You might consider using string stream:

std::stringstream ss;
ss << duration.count();
printf("%s", ss.str().c_str());

Solution 4:[4]

(Assuming you need to use printf())

Use an intermediate std::stringstream:

std::stringstream ss;
ss << "\n\nTime taken for simulation: " << duration.count() << "\n";
printf("%s",ss.str().c_str());
// or instead of the last line: puts(ss.str().c_str());

Solution 5:[5]

Consider using std::cout in all cases.

With regards to speed difference between the two, consider using:

std::ios::sync_with_stdio(false);

at the beginning of your code. This only works if you replace all your printf/scanf (and the like) usage with their C++ alternatives.

Using this should make the speed difference go away.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 eerorika
Solution 2
Solution 3 hyde
Solution 4 einpoklum
Solution 5 utnapistim