【问题标题】:Handle argc equal to 0处理 argc 等于 0
【发布时间】:2015-03-16 20:41:10
【问题描述】:

我最近看到了一些奇怪的东西。在 HHVM 源代码中,main() 函数的前 3 行如下所示:

if (!argc) {
  return 0;
}

这有点傻,但我还是忍不住想……为什么要返回 0!? 并不是我认为有一些正确的方法可以处理这个问题,而是返回 0,通常与成功联系在一起,似乎特别不合适。

除了不会崩溃之外,是否有曾经有对argc 为0 的适当响应的情况? (或者甚至小于 0?)这有关系吗?

我知道在 argc 为 0 的情况下结束的唯一方法是 exec() 和朋友。如果出于某种原因确实发生了这种情况,那几乎可以肯定是调用者中的一个错误,而被调用者对此无能为力。

(标记为 C 和 C++,因为我希望这两种语言的答案是相同的)

编辑:为了尽量减少问题的模糊性和哲学性,我将提供一个替代方案。

if (!argc) {
  puts("Error: argc == 0");
  return 1;
}

关键点是有错误指示并返回非零值。极不可能需要这样做,但如果是这样,您不妨尝试指出错误。另一方面,如果检测到的错误严重到argc 等于 0,那么尝试访问 stdout 或 C 标准库可能是有原因的。

【问题讨论】:

  • argc 按照标准必须是非负数。
  • 好吧,为什么不呢。它被要求什么都不做,它成功地什么都不做。
  • @HansPassant 是什么让你说它被要求什么都不做?当它被问到一个荒谬的问题时,我感到很震惊。
  • @Columbo 0 是非负数
  • @MattMcNabb ...你读过这个问题吗?我指的是“(甚至小于 0?)”。

标签: c++ c argc


【解决方案1】:

我认为这只是Defensive programming 的一个案例,因为HHVM 的源代码(文件hphp/hhvm/main.cpp)中有以下sn-p:

int main(int argc, char** argv) {
  if (!argc) {
    return 0;
  }
  HPHP::checkBuild();
  int len = strlen(argv[0]);

行内:

int len = strlen(argv[0]);

如果argc == 0 -> argv[0] == NULLstrlen(argv[0]) 将导致分段错误。

我不熟悉HHVM,但他们可以假设某些程序可以在没有参数的情况下调用该程序(甚至不是程序名称)。

【讨论】:

  • 这让我想知道:为什么if(!argc) return; 应该比分段错误更好?在任何一种情况下,进程都会立即停止,调用者必须处理失败。在分段错误的情况下,我们得到一个非零退出状态返回给调用者,这比 return 0; 假装一切都好。这只是关于避免段错误的宗教问题吗?
  • @cmaster strlen(argv[0]) 导致未定义的行为。这比分段错误有许多更糟糕的潜在后果。
  • @MM 好吧,如果argv[0]NULL(它必须是因为argv 是空终止的),strlen(argv[0]) 可以做除段错误之外的唯一方法是,如果你在一个脑死亡系统上,有人实际上已经映射了一些东西来解决零。即使有 一个页面和一些要读取的数据,所有strlen() 实现仍然会出现段错误或仅返回地址零处的非零字节数。语言律师说某事是未定义的行为并不意味着该行为是不可预测的。
  • @cmaster 当它是未定义的行为时,任何事情都可能发生。依赖特定编译器对 UB 的偶然处理只是无缘无故地给自己找麻烦。一个例子:有一些众所周知的错误实例,程序员预计会出现段错误,但优化器完全删除了该行。
  • @M.M 优化器无法删除strlen(argv[0]) 中的任何内容,因为调用必须在非空情况下工作。 UB 通过输入数据进入程序。段错误发生在strlen() 的实现中。
【解决方案2】:

请注意,C11 标准明确允许argc == 0

5.1.2.2.1 程序启动

¶1 程序启动时调用的函数名为main。实现声明没有 这个函数的原型。它应定义为返回类型int,并且没有 参数:

int main(void) { /* ... */ }

或带有两个参数(此处称为argcargv,尽管可以是任何名称 使用,因为它们在声明它们的函数中是本地的):

int main(int argc, char *argv[]) { /* ... */ }

或等效;10) 或以其他一些实现定义的方式。

¶2 如果它们被声明,main 函数的参数应遵循以下 约束:

  • argc 的值应为非负数。
  • argv[argc] 应为空指针。
  • 如果argc的值大于零,则数组成员argv[0]通过 argv[argc-1] inclusive 应包含指向字符串的指针,这些指针是给定的 在程序启动之前由主机环境实现定义的值。这 意图是向程序提供在程序启动之前确定的信息 来自托管环境中的其他地方。如果宿主环境不能 提供带有大写和小写字母的字符串,实现 应确保以小写形式接收字符串。
  • 如果argc的值大于零,则argv[0]指向的字符串 表示程序名argv[0][0] 应为空字符,如果 程序名称在主机环境中不可用。如果argc 的值为 大于一,argv[1]argv[argc-1] 指向的字符串 表示程序参数
  • argcargv 参数以及argv 数组指向的字符串应 可由程序修改,并在程序之间保留它们最后存储的值 启动和程序终止。

10) 因此,int 可以替换为定义为int 的typedef 名称,或者argv 的类型可以写为 char ** argv,等等。

“如果argc 的值大于零”这两个要点显然允许argc == 0,但这种情况并不常见。

因此,理论上,程序可以对其采取预防措施,尽管argv[0] == 0 即使argc == 0,只要代码不取消引用空指针,它应该没问题。许多程序,甚至大多数程序,都没有采取这种预防措施;他们假设argv[0] 不会是空指针。

【讨论】:

    猜你喜欢
    • 2013-12-15
    • 2023-03-23
    • 2013-05-01
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多