c - 在为所有枚举值定义大小写后,编译器仍然说 : "control reaches end of non-void function"

标签 c gcc enums switch-statement static-analysis

写一个简单的评估我遇到了一个有趣的问题。

给定代码:

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 接受原始代码 -(我想进行静态分析以了解我的代码是有效且干净的)。


编辑:

我可能有点不清楚。

假设我编译了以下代码:

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 了解开关中值的选项,以及我已经注释掉 LEAF 案例的事实。这意味着 gcc 也知道在通过 switch 时会检查每个案例。那么为什么声明:

control reaches end of non-void function

它是否缺少 gcc 中缺少的静态分析系统 - 或语言功能?

最佳答案

你的编译器在提示,因为你函数逻辑中的所有路径都应该返回一个值(正如这个函数的原型(prototype)所规定的):

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 语句具有与 NODELEAF 不同的值。


编辑:我试过这段代码:

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,编译为“C99 strict”)~ http://ideone.com/ou71fe : 无效因为:

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

并支持Martin Kristiansen关于为枚举分配任何整数值的观点是有效的,我已经尝试过 struct node n; n.type = 7; 使用相同的代码和“C”以及“C99 strict”,编译器根本不会提示。但是“C++”给出:

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

关于c - 在为所有枚举值定义大小写后,编译器仍然说 : "control reaches end of non-void function",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18680378/

相关文章:

c++ - 编译时抽象类处理中的 clang vs gcc

c - Scanf 在 C 中跳过每隔一个 while 循环

android - 进行选择查询时调用javaToSqlArg?

c - 函数的 IF 部分中的双重释放或损坏(顶部)

mysql - 在 Windows 7 上使用 libmysql.dll

c - 使用 Infinity 和 NaN 禁用异常

c++ - 将 double 舍入到最接近的非次正规表示

java - 在 JAVA 中为列表定义此枚举的构造函数?

c++ - 在 Protocol Buffer 中使用反射设置枚举值

c - strtok段错误,仅在输入文件的第一行为空时给出段错误