Olivier Esser
Olivier Esser

Reputation: 431

printf an integer of unknown precise type

I have put in my code a

typedef int myinteger ;

I want however all my code to continue to be valid if I change the typedef to another integer type.

Now I want to printf a variable of type myinteger. Is it a way to do it properly? I have just found the following "hack":

printf("%lld", myvariable) ;

hoping that any integer type will fit in a long long and that the compiler will do the proper conversion. It seems to works with gcc (although I have a warning). printf is a problem but they can be other problems too (like finding the maximum "myinteger").

More generally is it possible/desirable to try what I try to achieve, writing code assuming only that myinteger refers to some integer type?

Upvotes: 2

Views: 800

Answers (6)

chux
chux

Reputation: 154242

If all code needs to do is print the integer, and using C99 or C11, use _Generic to select the matching print specifier.

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

#define IntegerFormat3(X) _Generic((X), \
  size_t: "%zu", \
  ptrdiff_t: "%td", \
  default: 0 \
 )

#define IntegerFormat2(X) _Generic((X), \
  intmax_t: "%jd", \
  uintmax_t: "%ju", \
  default: IntegerFormat3(X) \
 )

#define IntegerFormat(X) _Generic(X, \
  _Bool: "%d", \
  char: "%c", \
  signed char: "%hhd", \
  unsigned char: "%hhu", \
  short: "%hd", \
  unsigned short: "%hu", \
  int: "%d", \
  unsigned: "%u", \
  long: "%ld", \
  unsigned long: "%lu", \
  long long: "%lld", \
  unsigned long long: "%llu", \
  default: IntegerFormat2(X) \
  )

int main(void) {
  int i = 12;
  unsigned long long u = 34;
  size_t sz = 56;
  printf(IntegerFormat(i), i);
  printf(IntegerFormat(u), u);
  printf(IntegerFormat(sz), sz);
  return 0;
}

Unfortunately printf(IntegerFormat(i) "\n", i); does not work.

Another C approach to formatted printing without any coded type dependent specifiers Formatted print without the need to specify type matching specifiers using _Generic.

Still, casting to the widest matching sign-ness type is simple as answered by others.

Upvotes: 0

autistic
autistic

Reputation: 15642

Consider branching depending on whether the value is negative, and casting to the intmax_t and uintmax_t types; there's no guarantee that long long int or unsigned long long int be the largest integer types, yet these max types are guaranteed to be the largest.

For example:

#include <inttypes.h>
/* ... */
if (my_variable < 0) printf("%jd", (intmax_t)  my_variable);
else                 printf("%ju", (uintmax_t) my_variable);

Upvotes: 1

mikedu95
mikedu95

Reputation: 1736

I recommend:

typedef int my_type_t;
#define FMT_MY_TYPE "%d"

Then:

my_type_t my_var = 0;
printf("Here is my_var: " FMT_MY_TYPE "\n", my_var);

This even works with structs. Here is a generalization:

typedef struct { int a; int b; } my_struct_t;
#define FMT_MY_STRUCT "{a: %d, b: %d}"
#define FMT_MY_STRUCT_ARG(x) (x).a, (x).b

Then:

my_struct_t my_var = {0, 1};
printf("Here is my_var: " FMT_MY_STRUCT "\n", FMT_MY_STRUCT_ARG(my_var));

Upvotes: 5

P.P
P.P

Reputation: 121427

There's no universal format specifier that can be used in printf() to print any integer type. One way is to cast to C99's intmax_t or uintmax_t and print it:

#include <stdint.h>

printf("%jd\n", (intmax_t)myvariable);
printf("%ju\n", (uintmax_t)myvariable);

This will work for all integer types as intmax_t/uintmax_t is the type maximum width integer.

In general, arbitrarily changing the typedef suggests there's a fundamental flaw in the design.

Upvotes: 5

ouah
ouah

Reputation: 145899

It seems to works with gcc (although I have a warning).

You need to add a cast.

printf("%lld", (long long) myvariable);

More generally is it possible/desirable to try what I try to achieve, writing code assuming only that "myinteger" refer to some integer type?

The "generic" printf call is a bad design smell. Moreover, what if myvariable is of type unsigned long long and its value is greater than LLONG_MAX?

Upvotes: 1

trojanfoe
trojanfoe

Reputation: 122458

You'd have to cast to long long in the call to printf() as it's the longest integer type:

printf("%lld", (long long)myvariable);

Upvotes: 1

Related Questions