после определения case для всех значений перечисления компилятор все еще говорит: "control достигает конца функции Non-void"
написание простой оценки я столкнулся с забавной проблемой.
данный код:
enum node_type {LEAF, NODE};
struct tree_elm_t {
enum node_type type;
union {
struct tree_node_t node;
struct tree_leaf_t leaf;
} datum;
};
int parse_leaf(struct tree_leaf_t leaf);
int parse_node( struct tree_node_t node );
int parse_tree( struct tree_elm_t* tree );
....
int parse_tree( struct tree_elm_t* tree ) {
switch( tree->type ) {
case NODE: return parse_node(tree->datum.node);
case LEAF: return parse_leaf(tree->datum.leaf);
}
}
Я был удивлен, увидев, что gcc жалуется на отсутствие опции потока управления:
example.c: In function 'parse_tree':
example.c:54: warning: control reaches end of non-void function
проблема потока может быть решена путем сохранить возвращаемое значение в переменной, вот так:
int parse_tree( struct tree_elm_t* tree ) {
int sum;
switch( tree->type ) {
case NODE: sum = parse_node(tree->datum.node); break;
case LEAF: sum = parse_leaf(tree->datum.leaf); break;
}
return sum;
}
Я, однако, нахожу исходный код более чистым, есть ли способ заставить gcc принять исходный код - (я хочу, чтобы статический анализ понял, что мой код действителен и чист).
EDIT:
Я, возможно, был немного неясно.
допустим, я компилирую следующий код:
int parse_tree( struct tree_elm_t* tree ) {
int sum;
switch( tree->type ) {
case NODE: sum = parse_node(tree->datum.node); break;
// case LEAF: sum = parse_leaf(tree->datum.leaf); break;
}
return sum;
}
gcc даст мне предупреждение:
example.c: In function 'parse_tree':
example.c:51: warning: enumeration value 'LEAF' not handled in switch
означает, что gcc имеет представление о параметрах значений в коммутаторе и о том, что я прокомментировал листовой случай. Это означало бы, что gcc также знает, что при переходе на коммутатор каждый случай рассматривается. так почему заявление:
control reaches end of non-void function
не хватает ли системы статического анализа в gcc-или языковой функции?
5 ответов
ваш компилятор жалуется, потому что все пути в логике вашей функции должны возвращать значение (как предписывает прототип этой функции):
int parse_tree( struct tree_elm_t* tree ) {
switch( tree->type ) {
case NODE: return parse_node(tree->datum.node);
case LEAF: return parse_leaf(tree->datum.leaf);
default: return 0; // <-- problem solved
}
}
компилятор (как и я в этом ответе) фокусируется скорее на синтаксисе, чем на семантике вашего кода.
и хотя вы определили enum node_type {LEAF, NODE}
, ваш компилятор не хочет полагаться на это ограничение и принимает возможность type
на tree->type
оператор, имеющий другое значение от just NODE
или LEAF
в любом случае.
EDIT: я пробовал этот код:
enum node_type {LEAF, NODE};
struct node { enum node_type type; };
int parse_tree( struct node* n ) {
switch( n->type ) {
case NODE: return 1;
case LEAF: return 2;
}
}
int main() {
struct node n;
printf("%d", parse_tree(&n));
return 0;
}
на ideone и результат следующий:
(gcc-4.8.1, скомпилированный как "C")~ http://ideone.com/b0wdSk: код действителен, выходы 2
(gcc-4.8.1, составлено как " C++") ~ http://ideone.com/OPH5Ar: то же, что и "C"
(на GCC-4.8.1, составленном как "С99 строгий") ~ http://ideone.com/ou71fe : инвалид из-за:
ошибка: управление достигает конца функции Non-void [- Werror=return-type]
и Мартин Кристиансено присвоении любого интегрального значения перечислению, которое является действительным, я попытался struct node n; n.type = 7;
С тем же кодом и с "C", но также и с "C99 strict" компилятор вообще не жалуется. Однако "С++" дает:
ошибка: недопустимое преобразование из ' int ' в 'node_type' [- fpermissive]
двусмысленность исходит из того, что в C enum
типы могут хранить другие значения, чем те, которые указаны в объявлении типа, и это в любом контексте, включая ваш switch
оператор, типизированный объект перечисления оценивается в int
. Вы можете избежать этого предупреждения с помощью
switch( tree->type ) {
case NODE: return parse_node(tree->datum.node);
default: return parse_leaf(tree->datum.leaf);
}
если вы думаете, что в дальнейшем развитии вы добавите другие случаи. Если нет, вам лучше пойти с bool
isNode
или что-то подобное.
чтобы предотвратить недостающее предупреждение о возврате с GCC, но по-прежнему получать предупреждения, если вы на самом деле отсутствует enum
case
, остановите поток управления после switch
заявление, но до конца функции.
В C вы можете использовать exit(int)
, quick_exit(int)
, _Exit(int)
или abort()
. (ссылка)
В C++ есть throw
expression - с или без надлежащего исключения в качестве аргумента. (ссылка)
Это также имеет преимущество определенного поведения в случае функция вызывается неправильно.
Clang не предупреждает о пропавших return
кстати.
добавить в случае дефолта.
switch( tree->type )
{
case NODE: return parse_node(tree->datum.node); break;
case LEAF: return parse_leaf(tree->datum.leaf); break;
default :
//perhaps throw exception here
return 0;
}
обратите внимание, что эта ситуация, вероятно, не требует оператора switch, if/else if, вероятно, то, что вы хотите.
есть ли какая-то причина, по которой это не сработает? (добавлено объявление):
void parse_leaf(struct tree_leaf_t leaf);
void parse_node( struct tree_node_t node );
void parse_tree( struct tree_elm_t* tree );
void parse_tree( struct tree_elm_t* tree ) {
switch( tree->type ) {
case NODE: parse_node(tree->datum.node); break;
case LEAF: parse_leaf(tree->datum.leaf); break;
}
}