1

I am using a library that returns a structure with a time stamp that is represented by two (TimestampHi, TimestampLo) unsigned longs. I pretty much only need the timestamp printed out as %llu in printf.

What's the easiest way to get the data from these two ints and correctly use it as a uint64_t?

Derrick
  • 2,356
  • 5
  • 32
  • 43
  • 2
    You should probably tag this with your OS/platform. Although you imply this to be the case in your situation, not all 64-bit platforms use a 32-bit `long`, some do use 64-bit. – Nicholas Knight Aug 13 '10 at 22:33
  • 2
    %llu is not the correct format for uint64_t. Cast the value to unsigned long long and use %llu, use 's PRIu64 macro or cast to uintmax_t and use %ju. – jilles Aug 13 '10 at 22:34

4 Answers4

10

Assuming that unsigned long long is a 64-bit type on your platform

assert(sizeof(unsigned long) * CHAR_BIT == 32);
assert(sizeof(unsigned long long) * CHAR_BIT == 64);
// Static asserts are more appropriate in cases like this

unsigned long long Timestamp = TimestampHi;
Timestamp <<= 32; Timestamp += TimestampLo; 

And then print the Timestamp value.

Same thing as an one-liner

unsigned long long Timestamp = ((unsigned long long) TimestampHi << 32) + TimestampLo; 

or simply

printf("%llu\n", ((unsigned long long) TimestampHi << 32) + TimestampLo);

If you wish to abstract your code from bit-based operations, the expression can be rewritten as

TimestampHi * ((unsigned long long) ULONG_MAX + 1) + TimestampLo
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I'd probably not bother with the `*CHAR_BIT`, but +1 for excruciating correctness. (Who has non-8-bit bytes anymore?) – zwol Aug 13 '10 at 22:32
  • @Zack: Various DSPs have 16- or 32-bit bytes. @AndreyT: is `unsigned long long` guaranteed not to have padding bits? – Steve Jessop Aug 13 '10 at 22:47
  • @Steve Jessop: Neither `unsigned long`, nor `unsigned long long` guaranteed not to have padding bits. So, of course, my assertions are not really checking what there were supposed to check. The above is written under assumption that they have no padding bits and/or that `unsigned long long` is sufficiently large to store a product of two arbitrary `unsigned long` values. – AnT stands with Russia Aug 13 '10 at 23:06
  • -1 for DSP pedantry when the OP specifically said 32-bit and 64-bit types. By the way, C99 requires `ULONG_MAX` to be at least 2^32-1 and `ULLONG_MAX` to be at least 2^64-1. So these types can be used without any ridiculous asserts to store 32-bit and 64-bit numbers (of course they may be bigger than needed). If you care, use `uint32_t` and `uint64_t`, or if you're really pedantic and worried they might not exist, use `uint_least32_t` and `uint_least64_t`. – R.. GitHub STOP HELPING ICE Aug 14 '10 at 05:57
  • If the platform really would not be standard conformant (C99 is not adopted everywhere, it seems) *and* your are extremely cautious about padding bits, going through `sizeof` in the assertions is probably the wrong way. Probably you should check if `(unsigned long)-1` and `(unsigned long long)-1` are `>=` to 2^32-1 and 2^64-1. – Jens Gustedt Aug 14 '10 at 06:22
  • 3
    `TimestampHi << 32ull` does *not* cause `TimestampHi` to be promoted to `unsigned long long`. The shift operators are a little different in this regard - the operands are promoted individually, and the type of the result is that of the promoted left operand (which in this case, will be unchanged). You need to use `(unsigned long long)TimestampHi << 32`. – caf Aug 14 '10 at 07:05
  • 1
    @R.: To be fair to AndreyT, he provides an assertion which, if it passes, ensures that the OP's assumption is true: long exactly 32 bits, long long exactly 64. It's wise to check such platform-assumptions, where possible. AndreyT's test has no false positives on conforming implementations - `assert(sizeof(long) == 4)` could have false positives (e.g. if `long` is 64 bit and `char` is 16-bit), so the use of CHAR_BIT is an improvement. Unfortunately the test could give false negatives where there are padding bits (e.g. 32-bit `long`, 9-bit `char`), as AndreyT acknowledges. I don't see a problem. – Steve Jessop Aug 14 '10 at 12:15
  • @caf: You are right. Thanks for the correction. I had my doubts (since `<<` is an "asymmetrical" operation), but forgot to check it. – AnT stands with Russia Aug 16 '10 at 16:24
4
unsigned long long t = (unsigned long long)hi << 32 | lo;
printf("%ull\n", t);

Note that I'm using unsigned long long instead of uint64_t because it's

  1. guaranteed to be at least 64 bits, and
  2. easy to print with printf - you don't need the PRIu64 macro, and
  3. you mentioned %ull in the question.

However, if you want to support MSVC (which is nowhere near conformant to modern standards), you might be better off with:

uint64_t t = (uint64_t)hi << 32 | lo;
printf("%" PRIu64 "\n", t);

This way you can ensure (via replacements for the missing system headers) that uint64_t is properly defined as MSVC's 64-bit unsigned type, and PRIu64 is defined as the proper printf format specifier to print it.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
1

Andrey answered what you do if you have some 64-bit type, but maybe you have only 32-bit types. In that case, what you need is a multi-precision integer library. The GNU MP library is excellent, but may be overkill for your purposes. I8lib implements "double" precision integer arithmetic (i.e. no more than 64 bits) and might do you fine, but i've never used it.

zwol
  • 135,547
  • 38
  • 252
  • 361
0

If the answer will be less than 2^49, and 64-bit ints aren't available, how about printf("%1.0f",4294967296.0*upper_part + lower_part)? That wouldn't work on platforms where a double is less than 64 bits, but it would work on many platforms without 64-bit ints.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • Why not separate the printing of the 2 parts using 2 calls to `sprintf`, then add them with ASCII addition? That way you just need 32 bits of precision in the mantissa. On the other hand, it's possible that your system's `printf` sucks and just prints garbage (e.g. zeros) in the low places after it's printed enough digits to uniquely determine the number. (See my question http://stackoverflow.com/questions/3215235/how-do-you-print-the-exact-value-of-a-floating-point-number) – R.. GitHub STOP HELPING ICE Aug 14 '10 at 06:02