Недостаточный анализ потока управления переключателем перечисления в GCC - PullRequest
10 голосов
/ 16 июня 2011

В следующем C ++ коде:

typedef enum { a, b, c } Test;

int foo(Test test) {
    switch (test) {
        case a: return 0;
        case b: return 1;
        case c: return 0;
    }
}

при компиляции с -Wall выдается предупреждение о том, что управление достигает конца не пустой функции. Почему?


Редактировать

Как правило, неправильно указывать, что переменная test в примере может содержать любое значение.

foo(12354) не компилируется:

> test.cpp:15:14: error: invalid conversion from ‘int’ to ‘Test’
> test.cpp:15:14: error:   initializing argument 1 of ‘int foo(Test)’

потому что 12354 не является действительным Test значением (хотя на самом деле будет действительным в виде простого C , но не в C ++).

Вы уверены, что могли бы явно привести произвольную целочисленную константу к типу enum, но разве это не считается неопределенным поведением?

Ответы [ 4 ]

5 голосов
/ 16 июня 2011

Проблема в том, что переменная типа Test может иметь любое значение, допустимое типом, который ей дает компилятор.Поэтому, если он решит, что это 32-разрядное целое число без знака, любое значение в этом диапазоне будет разрешено.Так, если, например, вы вызываете foo(123456), ваш оператор switch не будет перехватывать никакого значения, и после вашего switch.

не будет *1006*.некоторый код обработки ошибок.

4 голосов
/ 16 июня 2011

Хотя существует реальная опасность передачи foo аргумента, который не затронет ни одно из return утверждений, предупреждение не зависит от enum или от опасности. Вы можете увидеть тот же эффект с bool, в операторе switch, который (насколько я могу судить) абсолютно водонепроницаем.

В общем, компилятор не достаточно умен, чтобы определить, охватили ли вы все возможные пути, которые элемент управления мог бы фактически пройти через оператор switch. Чтобы быть таким умным, он должен был бы иметь возможность вывести все возможные состояния, которых может достичь программа, прежде чем войти в switch, что ведет прямо к проблеме остановки.

Таким образом, дедукция должна где-то остановиться, и (по крайней мере, с помощью gcc) она остановится с определением, что нет случая по умолчанию и что поэтому элемент управления может быть в состоянии покинуть switch без нажатия return.

3 голосов
/ 16 июня 2011

Нет никакой гарантии, что переменная test будет содержать действительное перечисление, так что фактически вы можете достичь конца вашей не пустой функции, например, если ваш код вызова выглядит так:

Test test = Test(3);
foo(test);
1 голос
/ 16 июня 2011

Хотя ваш enum имеет только три объявленных состояния, реализация фактически выберет больший целочисленный тип (обычно int) для хранения значений, которые НЕ ограничены объявленными.Стандарт просто дает некоторые минимальные гарантии, чтобы гарантировать, что он может по крайней мере обрабатывать указанные значения и определенные комбинации.Иногда эта свобода необходима, так как значения enum предназначены для побитового ИЛИ для формирования комбинаций.Таким образом, функция foo может быть вызвана, скажем, Test(3), которая не найдет оператор return в вашем switch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...