26 votes

Emuler __builtin_unreachable de GCC ?

J'ai tout un lot d'avertissements sur les commutations qui ne couvrent que partiellement la plage d'une énumération commutée. Par conséquent, j'aimerais avoir un "défaut" pour tous ces commutateurs et mettre __builtin_unreachable (GCC builtin) dans ce cas, afin que le compilateur sache que ce cas n'est pas atteignable.

Cependant, j'ai appris que GCC4.3 ne supporte pas encore ce buildin. Existe-t-il un bon moyen d'émuler cette fonctionnalité ? J'ai pensé à déréférencer un pointeur nul à la place, mais cela peut avoir d'autres effets indésirables / avertissements et autres. Avez-vous une meilleure idée ?

12voto

FUZxxl Points 21462

Vous pouvez appeler une fonction en ligne déclarée _Noreturn pour marquer tout ce qui suit cet appel comme inaccessible. Le compilateur est autorisé à rejeter tout code après une telle fonction. Si la fonction elle-même est static (et renvoie), le compilateur va généralement aussi mettre la fonction en ligne. Voici un exemple :

static _Noreturn void unreachable() {
    return; /* intentional */
}

/* ... */

foo();
bar(); /* should better not return */
unreachable();
baz(); /* compiler will know this is not reachable */

Notez que vous invoquez un comportement indéfini si une fonction marquée _Noreturn revient en effet. Soyez sûr que cette fonction ne sera jamais appelée.

8voto

janneb Points 17303

Hmm, quelque chose comme (depuis l'apparition de __builtin_unreachable() en 4.5) :

#define GCC_VERSION (__GNUC__ * 10000 \
                               + __GNUC_MINOR__ * 100 \
                               + __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= 40500
#define my_unreachable()  __builtin_unreachable()
#else
#define my_unreachable() do { printf("Oh noes!!!111\n"); abort(); } while(0)
#endif

4voto

Mark B Points 60200

Serait-ce abort (laissant un core dump) ou throw (permettant une saisie alternative des données) répondent à vos besoins ?

Voulez-vous vraiment avoir des instructions de commutation qui ne couvrent pas l'énumération complète ? J'essaie presque toujours de lister tous les cas possibles (jusqu'au no-op) sans aucun cas par défaut afin que gcc me prévienne si de nouvelles énumérations sont ajoutées, car il peut être nécessaire de les gérer plutôt que de les laisser tomber silencieusement (pendant la compilation) dans le cas par défaut.

3voto

CAFxX Points 3911

Restez simple :

assert(false);

ou, mieux encore :

#define UNREACHABLE (!"Unreachable code executed!")

assert(UNREACHABLE);

2voto

iammilind Points 29275
template<unsigned int LINE> class Unreachable_At_Line {}; 
#define __builtin_unreachable() throw Unreachable_At_Line<__LINE__>()

Modifier :

Puisque vous voulez que le code inaccessible soit omis par le compilateur, voici la méthode la plus simple.

#define __builtin_unreachable() { struct X {X& operator=(const X&); } x; x=x; }

Le compilateur optimise x = x; surtout quand elle est inaccessible. Voici l'utilisation :

int foo (int i)
{
  switch(i)
  {
  case 0:  return 0;
  case 1:  return 1;
  default: return -1;
  }
  __builtin_unreachable();  // never executed; so compiler optimizes away
}

Si vous mettez __builtin_unreachable() au début de foo() alors le compilateur génère un erreur de liaison pour les projets non mis en œuvre operator = . J'ai effectué ces tests avec gcc 3.4.6 (64 bits).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X