Подтвердить что ты не робот

Эмуляция GCC __builtin_unreachable?

Я получаю много предупреждений о коммутаторах, которые только частично покрывают диапазон перечислимого перечисления. Поэтому я хотел бы иметь "по умолчанию" для всех этих коммутаторов и поставить в этом случае __builtin_unreachable (GCC builtin), чтобы компилятор знал, что этот случай недоступен.

Однако я узнал, что GCC4.3 еще не поддерживает эту встроенную систему. Есть ли хороший способ подражать этой функциональности? Я думал о разыменовании нулевого указателя, но это может иметь другие нежелательные эффекты/предупреждения и т.д. У вас есть идея?

4b9b3361

Ответ 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);