问题 处理argc等于0


我最近看到一些好奇的东西。在HHVM源代码中,前3行 main() 功能如下:

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标准库是不好的。


10748
2018-01-18 20:32


起源

argc 按标准要求是非负的。 - Columbo
好吧,为什么不呢。它被要求什么都不做,它没有成功。 - Hans Passant
@HansPassant是什么让你说它被要求什么都不做?它引起了我的兴趣,因为它被问到一个荒谬的问题。 - Praxeolitic
@Columbo 0 是非消极的 - M.M
@MattMcNabb ...你读过这个问题吗?我指的是“(或者甚至不到0?)”。 - Columbo


答案:


我认为这只是一个例子 防守编程 由于下面的代码片段 HHVM的代码(文件 HPHP / HHVM / main.cpp中):

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] == NULL 和 strlen(argv[0]) 会导致分段错误。

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


4
2018-01-19 00:03



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


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

5.1.2.2.1程序启动

¶1程序启动时调用的函数被命名 main。实施宣布否   这个功能的原型。它应定义为返回类型 int 没有   参数:

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

或者有两个参数(这里称为 argc 和 argv,虽然任何名字都可能   使用,因为它们是声明它们的函数的本地):

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

或同等学历;10) 或者以其他一些实现定义的方式。

¶2如果它们被声明,则参数为 main 功能应遵守以下规定   限制:

  • argc的值应为非负值。
  • argv[argc] 应该是一个空指针。
  • 如果值 argc 大于零的数组成员 argv[0] 通过    argv[argc-1] 包含应包含指向字符串的指针   程序启动前主机环境实现定义的值。该   意图是在程序启动之前为程序提供信息   来自托管环境中的其他地方。如果主机环境不具备   为字符串提供大写和小写的字母,实现   应确保以小写字母收到字符串。
  • 如果值 argc大于零,字符串指向 argv[0]   代表着 程序名称; argv[0][0] 如果是,则应为空字符   程序名称不能从主机环境中获得。如果值 argc 是   大于一,指向的字符串 argv[1] 通过 argv[argc-1]   代表 程序参数
  • 参数 argc 和 argv 和指向的字符串 argv 阵列应   可以由程序修改,并在程序之间保留它们最后存储的值   启动和程序终止。

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

这两个要点是'如果有价值的话 argc '大于零''明确允许 argc == 0虽然这种情况很不寻常。

因此,从理论上讲,一个程序可以采取预防措施 argv[0] == 0 即使 argc == 0,所以只要代码不取消引用空指针,它应该没问题。许多计划,甚至大多数计划,都没有采取这些预防措施;他们认为 argv[0] 不会是空指针。


6
2018-01-19 07:32