警告“返回”无值,函数返回非空-返回什么?

时间:2018-08-12 08:12:07

标签: c error-handling compiler-warnings gcc-warning

如何解决以下在标题中引发警告的问题?

struct Nodes* InsertNode(unsigned int IP, unsigned short Port)
{
    if (!IP)
       return;
    if (!Port)
       return;
    // Above is what chucks the warnings
    {
        // do stuff & conditionally
           return &List[x];
    }
    // Different conditions & stuff
    {
       return &List[Other];
    }
}

换句话说,如果放弃丢失的数据,它应该返回什么?还是我需要遍历整个代码主体并每次都进行检查以查看是否应调用它?该程序将按原计划返回功能,如果我要继续使用它(或升级正在运行的操作系统),修复编译器警告似乎是一个好主意,当编译器版本受阻时,它们往往会变成错误。

this answer中有一条线索可以回答某人询问相同的警告,但是该答案并没有给我足够的信息以继续进行下去,也没有给我提供其他信息。

其他信息:检查 IP Port 的值可以清除&List 的内容,这种情况表示数据报来自客户端配置错误或来自有恶意意图的人的流量,令人难过,但它确实发生了。这是我们根本不在乎的 无效数据,记录它似乎毫无意义,它不应延迟处理下一个数据,并且绝对不要暂停程序。从gcc 4.9切换到6.3之前,我没有看到警告。当前的返回; 似乎是,只是对其进行了黑洞处理,但我只了解代码的意图。

2 个答案:

答案 0 :(得分:2)

  

如果放弃丢失的数据,应该返回什么?

视情况而定。

有几种情况

  1. 该函数不能设计为返回NULL作为有效值。

    替换

    if (!IP)
      return;
    if (!Port)
      return;
    

    作者

    if (!IP || !Port)
    {
      errno = EINVAL; /* Setting errno, allows the caller to log 
                         the failure using the perror() function. */
      return NULL;
    }
    

    像这样使用它:

    struct Nodes * p = InsertNode (...);
    if (NULL == p)
    {
       perror("InsertNode() failed");
       /* exit or error logging/handling */
    }
    
  2. 在正常操作下,
  3. IPPort永远不会是0。因此,如果是这样,那就是编程错误。

    在这种情况下,您可能不会不返回而是结束程序。

    所以不是

    if (!IP)
      return;
    if (!Port)
      return;
    

    使用

    assert((IP) && (Port));
    

    这里没有特定的用法,因为如果不满足断言,程序只会结束。

    注意,此方法需要广泛的测试,因为通常会在生产/发布版本中删除该测试!

  4. 函数可能返回NULL作为有效值 IP和/或Port may 在正常操作下为0

    将功能重新设计为以一种方式或另一种方式返回单独的错误状态。

    通常可以通过两种方式完成此操作:

    • 使用函数的返回值,并通过作为参数传递的指针将结果传回

      int InsertNode(unsigned int IP, unsigned short Port, struct Nodes** ppresult)
      {
        int error_state = 0;
      
        if (!IP || !Port || !ppresult)
        {
          errno = EINVAL; /* Setting errno, allows the caller to log 
                         the failure using the perror() function. */
          error_state = -1;
        }
        else
        {
          if (...)
          {
            *ppresult = &List[x];
          }
      
          ...
      
        }
      
        return error_state;
      }
      

      像这样使用它:

      struct Nodes * p;
      if (-1 == InsertNode (..., &p))
      {
         perror("InsertNode() failed");
        /* exit or error logging/handling */
      }
      
    • 通过作为参数传递的指针传回错误状态结果

      struct Nodes * InsertNode(unsigned int IP, unsigned short Port, int * perror_state)
      {
        int error_state = 0;
      
        if (!IP || !Port || !perror_state)
        {
          errno = EINVAL; /* Setting errno, allows the caller to log 
                         the failure using the perror() function. */
          error_state = -1;
        }
        else
        {
          if (...)
          {
            *ppresult = &List[x];
          }
      
          ...
      
        }
      
        *perror_state = error_state;
      
        return NULL;
      }
      

      像这样使用它:

      int result;
      struct Nodes * p = InsertNode (..., &result))
      if (-1 == result)
      {
        perror("InsertNode() failed");
        /* exit or error logging/handling */
      }
      

答案 1 :(得分:0)

TLDR

“直到从gcc 4.9切换到6.3为止,我都没有看到警告。”尝试使用gcc -std=gnu90进行编译,以在与之前使用gcc 4.9时类似的条件下进行编译。

好,我在听音乐

在将编译器从gcc 4.9更改为gcc 6.3后看到编译器警告的原因是gcc 4.9默认为C90(实际上是C90的gnu90方言),但gcc 5.5则默认为C11(实际上是gnu11)。

C90标准在约束部分中说明了return语句,(C90§6.6.6.4):

  

带有表达式的 return 语句不应出现在返回类型为 void 的函数中。

但是C11标准中相同的约束部分说C11 §6.8.6.4

  

带有表达式的 return 语句不应出现在返回类型为 void 的函数中。 没有表达式的 return 语句只能出现在返回类型为 void 的函数中。

现在,编译器必须针对任何约束违反(§5.1.1.3)生成诊断消息。在C90下编译您的代码时,没有违反任何约束,但是更改为较新的编译器意味着该代码现在可以在C11下进行编译,其中存在 约束,因此出现警告。

一种选择是简单地使用gcc -std=gnu90进行编译,从而允许使用与以前使用的C语言相同的方言来编译代码,即使是在较新的编译器上。

但是,还要注意,自(C90§6.6.6.4)起,原始代码可能具有未定义的行为

  

如果执行带有表达式的 return 语句,并且调用者使用了函数调用的值,则行为是不确定的。

如果调用者使用了InsertNode()返回的值,并且在函数调用中遇到了return;语句,则您的行为不确定。最好的选择是查看对InsertNode()的所有调用,以了解它们如何处理返回值。 return;可能是一个错字,并且该代码已经可以处理返回的空指针,在这种情况下,只需修改return NULL;就可以修复该代码。如果代码尚未处理空指针,请使用@alk has provided several options来修复代码。