After defining a case for all enum values, the compiler still says: "control reaches the end of the non-void function"

Writing a simple grade I ran into a fun problem.

Based on the code:

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); } } 

I was surprised to see gcc complaining about a missing control flow option:

 example.c: In function 'parse_tree': example.c:54: warning: control reaches end of non-void function 

a thread problem can be solved by storing the return value in a variable like this:

 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; } 

However, I found the alot cleaner source code, there is a way to make gcc accept the source code - (I want static analysis to understand that my code is valid and clean).


EDIT:

Perhaps I was a little obscure.

allows you to compile the following code:

 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 will give me a warning:

 example.c: In function 'parse_tree': example.c:51: warning: enumeration value 'LEAF' not handled in switch 

means that gcc makes sense of options for values ​​in the switch and the fact that I hav commented on the case of LEAF. This would mean that gcc also knows that when moving through the switch, each case is considered. therefore why the statement:

 control reaches end of non-void function 

Is there no static analysis system in gcc or language function?

+6
source share
5 answers

Your compiler complains because all the paths in your function logic must return a value (since the prototype of this function requires):

 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 } } 

The compiler (like me in this answer) focuses more on the syntax than on the semantics of your code.

And although you have defined enum node_type {LEAF, NODE} , your compiler does not want to rely on this restriction and allows the possibility of type in tree->type , which has a different value only from NODE or LEAF in any case.


EDIT: I tried this code:

 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; } 

on ideon, and the result is as follows:
(gcc-4.8.1, compiled as "C") ~ http://ideone.com/b0wdSk : code is valid, outputs 2
(gcc-4.8.1 compiled as "C ++") ~ http://ideone.com/OPH5Ar : same as "C"
(gcc-4.8.1, compiled as "C99 strict") ~ http://ideone.com/ou71fe : invalid due to:

error: control reaches the end of the non-void function [-Werror = return-type]

And to support Martin Christiansen about assigning any integer value to an enumeration that is valid, I tried struct node n; n.type = 7; struct node n; n.type = 7; with the same code and with "C", but also with "C99 strict", the compiler does not complain at all. However, "C ++" gives:

error: invalid conversion from 'int to' node_type [-fpermissive]

+7
source

The ambiguity arises due to the fact that in C enum types can store different values ​​than those specified in the type declaration, and that in any context, including your switch , an enumerated object enters an int value. You can avoid this warning with

  switch( tree->type ) { case NODE: return parse_node(tree->datum.node); default: return parse_leaf(tree->datum.leaf); } 

if you think that with further development you will add other cases. If not, you'd better go with bool isNode or something like that.

+1
source

To prevent the GCC from returning a warning, but still get warnings if the enum case is actually missing, stop the control flow after the switch , but until the end of the function.
In C, you can use exit(int) , quick_exit(int) , _Exit(int) or abort() . ( reference )
In C ++, there is a throw expression - with or without the right exception as an argument. ( reference ) This also has the advantage of certain behavior in the event of a malfunctioning function.

Clang does not warn about the lack of return btw.

+1
source

Add to default case.

 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; } 

Note that this situation probably does not need a switch statement if / else if, perhaps you want to.

0
source

Is there a reason this will not work? (added ads):

 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; } } 
-2
source

Source: https://habr.com/ru/post/953415/


All Articles