J'ai mis dans mon code un

typedef int myinteger ;

Je veux cependant que tout mon code continue à être valide si je change le typedef en un autre type entier.

Maintenant, je veux imprimer une variable de type myinteger. Est-ce un moyen de le faire correctement? Je viens de trouver le "hack" suivant:

printf("%lld", myvariable) ;

En espérant que tout type entier rentrera dans un long long et que le compilateur effectuera la conversion appropriée. Cela semble fonctionner avec gcc (bien que j'aie un avertissement). printf est un problème mais ils peuvent aussi être d'autres problèmes (comme trouver le maximum "myinteger").

Plus généralement, est-il possible / souhaitable d'essayer ce que j'essaie de réaliser, en écrivant du code en supposant uniquement que myinteger fait référence à un type entier?

c
2
Olivier Esser 31 déc. 2015 à 13:49

6 réponses

Meilleure réponse

Je recommande:

typedef int my_type_t;
#define FMT_MY_TYPE "%d"

Alors:

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

Cela fonctionne même avec les structures. Voici une généralisation:

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

Alors:

my_struct_t my_var = {0, 1};
printf("Here is my_var: " FMT_MY_STRUCT "\n", FMT_MY_STRUCT_ARG(my_var));
4
mikedu95 31 déc. 2015 à 11:46

Il n'y a pas de spécificateur de format universel qui puisse être utilisé dans printf() pour imprimer n'importe quel type entier. Une méthode consiste à diffuser sur C99 intmax_t ou uintmax_t et à l'imprimer:

#include <stdint.h>

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

Cela fonctionnera pour tous les types d'entiers car intmax_t / uintmax_t est l'entier de largeur maximale du type.

En général, changer arbitrairement le typedef suggère qu'il y a un défaut fondamental dans la conception.

4
P.P 31 déc. 2015 à 10:58

Vous devrez effectuer un cast vers long long lors de l'appel vers printf() car il s'agit du type entier le plus long:

printf("%lld", (long long)myvariable);
1
trojanfoe 31 déc. 2015 à 10:52

Cela semble fonctionner avec gcc (bien que j'aie un avertissement).

Vous devez ajouter une distribution.

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

Plus généralement, est-il possible / souhaitable d'essayer ce que j'essaie de réaliser, en écrivant du code en supposant seulement que "myinteger" fait référence à un type entier?

L'appel "générique" printf est une mauvaise odeur de design. De plus, que se passe-t-il si myvariable est de type unsigned long long et que sa valeur est supérieure à LLONG_MAX?

1
ouah 31 déc. 2015 à 10:52

Envisagez de créer des branches selon que la valeur est négative et de transtyper vers les types intmax_t et uintmax_t; il n'y a aucune garantie que long long int ou unsigned long long int soient les plus grands types d'entiers, mais ces types max sont garantis pour être les plus grands.

Par exemple:

#include <inttypes.h>
/* ... */
if (my_variable < 0) printf("%jd", (intmax_t)  my_variable);
else                 printf("%ju", (uintmax_t) my_variable);
1
autistic 31 déc. 2015 à 19:51

Si tout ce que le code doit faire est d'imprimer l'entier, et en utilisant C99 ou C11, utilisez _Generic pour sélectionner le spécificateur d'impression correspondant.

#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;
}

Malheureusement, printf(IntegerFormat(i) "\n", i); ne fonctionne pas.

Une autre approche C de l'impression formatée sans aucun spécificateur dépendant du type codé Impression formatée sans qu'il soit nécessaire de spécifier des spécificateurs de correspondance de type en utilisant _Generic.

Pourtant, le cast vers le type de signature correspondant le plus large est simple comme l'ont répondu d'autres.

0
Community 13 avril 2017 à 12:40