Эмулировать GCC __builtin_unreachable? - PullRequest
23 голосов
/ 17 мая 2011

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

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

Ответы [ 5 ]

8 голосов
/ 15 марта 2014

Вы можете вызвать встроенную функцию, объявленную _Noreturn, чтобы пометить что-либо после этого вызова как недоступное.Компилятору разрешено выбрасывать любой код после такой функции.Если сама функция static (и действительно возвращает), компилятор обычно также вставляет функцию в строку.Вот пример:

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

/* ... */

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

Обратите внимание, что вы вызываете неопределенное поведение, если функция, отмеченная _Noreturn, действительно возвращает.Убедитесь, что указанная функция никогда не будет вызвана.

7 голосов
/ 17 мая 2011

Хм, что-то вроде (так как __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

3 голосов
/ 17 мая 2011
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-bit).

3 голосов
/ 17 мая 2011

Будет ли abort (оставляя дамп ядра) или throw (с учетом альтернативного захвата данных) соответствовать вашим потребностям?

Вы действительно хотите иметь операторы switch, которые не охватывают полное перечисление? Я почти всегда пытаюсь перечислить все возможные случаи (без опций) без случая по умолчанию, так что gcc предупредит меня, если будут добавлены новые перечисления, так как может потребоваться обработать их, вместо того, чтобы он падал тихо (во время компиляции) по умолчанию.

2 голосов
/ 17 мая 2011

не усложняйте:

assert(false);

или, еще лучше:

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

assert(UNREACHABLE);
...