带有返回的If语句代码样式

if statement code style with returns

本文关键字:语句 代码 样式 If 返回      更新时间:2023-10-16

假设我有这样的函数:

inline bool fileExists(const char *name) {
  FILE *file;
  if (fopen_s(&file, name, "r") == 0)
  {
    fclose(file);
    return true;
  } else {
    return false;
  }
}

做上面那个好,还是做这个好?

inline bool fileExists(const char *name) {
  FILE *file;
  if (fopen_s(&file, name, "r") == 0)
  {
    fclose(file);
    return true;
  }
  return false;
}

在编译时是否存在差异?

这主要是意见问题。在我看来,第二种形式更好,因为它总是提供返回值。如果在else子句中修改函数做一些不同的事情,您可能会忘记添加返回值。在上面的示例中,生成的代码是相同的。

效率不是问题。一个像样的编译器应该知道该怎么做。对于这个简单的函数,逻辑上应该是一样的。但是对于更大的函数,有更多的逻辑,第二种方法稍微好一些,因为它保证函数总是返回。

或者选择单点返回(这并不一定适用于这里,因为函数相对较小)。这可以帮助编译器生成更好、更高效的代码,在某些情况下(多个返回语句阻碍RVO):

inline bool fileExists(const char *name) {
  FILE *file;
  bool exists = false;
  if (fopen_s(&file, name, "r") == 0)
  {
    fclose(file);
    exists = true;
  }
  return exists;
}

不,编译器的语义分析,以及之后的优化器,将得到相同的目标代码。

在这种特殊情况下,绝对不是问题。fopen将花费微秒(除非包含实际文件的目录没有缓存,在这种情况下需要几毫秒),并且您担心是否会有一个额外的跳转—可能是4-6个时钟周期。

一般来说,我更喜欢"一个返回语句",但它有时会变得相当混乱,在这种情况下,我更喜欢第二个选项。几乎总是,代码会变成这样,因为"编译器"也更喜欢单个出口点:

bool fileExists(const char *name) {
  FILE *file;
  bool ret_val;
  if (fopen_s(&file, name, "r") == 0)
  {
    fclose(file);
    ret_val = true;
    goto end;
  }
  ret_val = false
end:
  return ret_val;
}

有时候,如果代码非常复杂——特别是如果代码"开始很简单",然后变得复杂,编译器将从函数中获得多个返回点,但上面的场景是相当典型的。我并不是建议你在代码中使用goto。编译器完全有能力做出改变]

哦,我怀疑在这种情况下使用inline并不会对性能产生太大的影响。