c++ - ¿Emulando__builtin_unreachable de GCC?
unreachable-code (5)
¿ abort
(dejando un volcado de memoria) o throw
(permitiendo la captura de datos alternativos) se adaptaría a sus necesidades?
¿Realmente desea tener declaraciones de cambio que no cubran la enumeración completa? Casi siempre trato de enumerar todos los casos posibles (no operativo) sin un caso predeterminado para que gcc me advierta si se agregan nuevas enumeraciones, ya que puede ser necesario manejarlas en lugar de dejarlas en silencio (durante la compilación) en el valor predeterminado.
Recibo muchas advertencias sobre los conmutadores que solo cubren parcialmente el rango de una enumeración cambiada. Por lo tanto, me gustaría tener un "valor predeterminado" para todos esos conmutadores y poner __builtin_unreachable
(GCC builtin) en ese caso, para que el compilador sepa que no se puede __builtin_unreachable
caso.
Sin embargo, llegué a saber que GCC4.3 aún no es compatible con esa función incorporada. ¿Hay alguna buena manera de emular esa funcionalidad? Pensé en desreferenciar un puntero nulo en su lugar, pero eso puede tener otros efectos / advertencias no deseados y demás. ¿Tienes alguna idea mejor?
Hmm, algo como (ya que __builtin_unreachable () apareció 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
Puede llamar a una función en línea declarada _Noreturn
para marcar cualquier cosa después de esa llamada como inaccesible. El compilador tiene permitido tirar cualquier código después de dicha función. Si la función en sí es static
(y regresa), el compilador generalmente también integrará la función. Aquí hay un ejemplo:
static _Noreturn void unreachable() {
return; /* intentional */
}
/* ... */
foo();
bar(); /* should better not return */
unreachable();
baz(); /* compiler will know this is not reachable */
Observe que invoca un comportamiento indefinido si una función marcada con _Noreturn
devuelve. Asegúrese de que dicha función nunca será llamada.
mantenlo simple:
assert(false);
o mejor aún:
#define UNREACHABLE (!"Unreachable code executed!")
assert(UNREACHABLE);
template<unsigned int LINE> class Unreachable_At_Line {};
#define __builtin_unreachable() throw Unreachable_At_Line<__LINE__>()
Editar :
Dado que desea que el compilador omita el código inalcanzable, a continuación se muestra la forma más sencilla.
#define __builtin_unreachable() { struct X {X& operator=(const X&); } x; x=x; }
El compilador optimiza lejos x = x;
Instrucción especialmente cuando es inalcanzable. Aquí está el uso:
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 coloca __builtin_unreachable()
al comienzo de foo()
, el compilador genera un error de vinculador para el operator =
no implementado operator =
. Ejecuté estas pruebas en gcc 3.4.6 (64 bits).