Эмуляция GCC __builtin_unreachable?
Я получаю много предупреждений о коммутаторах, которые только частично покрывают диапазон перечислимого перечисления. Поэтому я хотел бы иметь "по умолчанию" для всех этих коммутаторов и поставить в этом случае __builtin_unreachable
(GCC builtin), чтобы компилятор знал, что этот случай недоступен.
Однако я узнал, что GCC4.3 еще не поддерживает эту встроенную систему. Есть ли хороший способ подражать этой функциональности? Я думал о разыменовании нулевого указателя, но это может иметь другие нежелательные эффекты/предупреждения и т.д. У вас есть идея?
Ответы
Ответ 1
Хмм, что-то вроде (поскольку __builtin_unreachable() появился в 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
Ответ 2
Вы можете вызвать встроенную функцию, объявленную _Noreturn
, чтобы отметить что-либо после этого вызова как недоступное. После такой функции компилятору разрешается выкидывать любой код. Если сама функция static
(и возвращается), компилятор обычно также встроит эту функцию. Вот пример:
static _Noreturn void unreachable() {
return; /* intentional */
}
/* ... */
foo();
bar(); /* should better not return */
unreachable();
baz(); /* compiler will know this is not reachable */
Обратите внимание, что вы вызываете поведение undefined, если функция, помеченная _Noreturn
, действительно возвращает. Убедитесь, что указанная функция никогда не будет вызвана.
Ответ 3
Будет ли abort
(оставляя дамп ядра) или throw
(позволяющий чередовать сбор данных) удовлетворить ваши потребности?
Вы действительно хотите иметь инструкции switch, которые не охватывают полное перечисление? Я почти всегда пытаюсь перечислить все возможные случаи (без-op) без случая по умолчанию, так что gcc предупредит меня, если будут добавлены новые перечисления, так как может потребоваться обработать их, а не позволить ему тихо (во время компиляции) упасть в значение по умолчанию.
Ответ 4
template<unsigned int LINE> class Unreachable_At_Line {};
#define __builtin_unreachable() throw Unreachable_At_Line<__LINE__>()
Изменить:
Поскольку вы хотите, чтобы компилятор не удалял недостижимый код, ниже самый простой способ.
#define __builtin_unreachable() { struct X {X& operator=(const X&); } x; x=x; }
Компилятор оптимизирует команду x = x;
, особенно когда она недоступна. Вот использование:
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
}
Если вы положили __builtin_unreachable()
в начало foo()
, тогда компилятор генерирует ошибку компоновщика для нереализованного operator =
. Я провел эти тесты в gcc 3.4.6 (64-разрядный).
Ответ 5
держите его просто:
assert(false);
или, еще лучше:
#define UNREACHABLE (!"Unreachable code executed!")
assert(UNREACHABLE);