< home

i64_printf

last updated: 16062010


the issue:

not really being an issue...in C (gcc) you will normally printf() a 64bit integer with the following line:


printf("%ull\n", number);

mingw, however, uses the microsoft formating, which is:

printf("%I64u\n", number);
/* as part of 'ms_printf' */

to write your code portable in that aspect you can use the PRI* macros found in "inttypes.h" (suggested by Michael Gruhn):

printf("%"PRIu64"\n", x);

/*
 the "PRIu64" macro should expand to:
 - "I64u" on mingw
 - "ull" on gcc
*/

or
you can try something like:

/* 'm' is the printf modifier */
#ifdef __MINGW__
  #define i64_printf(x, m) printf("%I64"m"d\n", x);
#else
  #define i64_printf(x, m) printf("%"m"ll\n", x);
#endif
/*
  e.g. usage:
  compile with -std=c99 (or it will produce a warning)
  i64_printf(11111111111111111111ULL, "u");

*/


alternatively (and for fun) if you don't want to use preprocessor macros here or like the 'I64' modifier much, you can try the following:

/*
 
compile with -std=c99
*/

#include <stdio.h>
#include <stdint.h>
#include <limits.h>

inline void int64_printf (const register uint64_t v, const uint8_t mode)
{
  /* mode = 1 -> hex */  
  if (mode == 1)
  {
    if (v > 0xffffffff)
      printf("%#010x%010x\n", (uint32_t)(v >> 32), (uint32_t)v);
    else
      printf("%#018x\n", (uint32_t)v);
  }
  else
  {
    /* mode = 0 (or any) -> decimal */
    register uint8_t e = 0;
    register uint64_t ve = v;
    while (ve)
    {
      ve /= 10;
      e++;
    }
    e >>= 1;
    ve = 1;
    while (e--)
      ve *= 10;
    printf("%u%u\n", (uint32_t)((v / ve)), (uint32_t)(v % ve));
  }
}

example:

uint64_t x = 11111111111111111111ULL;
i64_printf(x, 1);
/* output is 0x9a3298afb5ac71c7 */
i64_printf(x, 0);
/* output is 184467440737055112 */

how it works:
the hex version first tries to find if the input value is larger than 32bit. if so we just shift the value by 32 (v >> 32) and print the high bits first then we print the lower bits by truncating the value to 32 bits (uint32_t)(v).

the decimal version performs a log10 to find the exponent (e) of the input. then splits the exponent in half so that we can first print the integer from the division of (v / pow(10, e/2) ) and following that we also print the integer remainder from the modulus ( v %
pow(10, e/2) ). again first print higher bits then lower bits.

for binary, octal or other types you can use similar principals - split lower / higher bits into two or more groups:

a rough example for octal (not included in the download bellow):

/*
  octal
  v is the input
*/
uint64_t b[100];
register uint16_t j = 0, k, i; /* iterators */
register uint64_t _v = 0, p;
while (v)
{
  b[j++] = v % 8; /* store remainder in array */
  v /= 8;
}
while (j)
{
  k = j - 1;
  p = 1;
  i = k;
  while (i--) /* pow10 */
    p *= 10;
  _v += b[k] * p; /* multiply remainder by the exponent and add to _v */
  j--;
}
v = _v;
/* the result in v is the (decimal -> octal) conversation */

download:

i64_printf.c


contact:

lubomir i. ivanov
neolit123 [at] gmail