为什么命令行参数计数变量(传统上为 argc
)是 int
而不是 unsigned int
?这有技术原因吗?
在尝试摆脱所有已签名的未签名比较警告时,我总是忽略它,但从不明白为什么会这样。
事实上,原始 C 语言默认情况下任何变量或参数都定义为 int 类型,这可能是另一个因素。换句话说,您可以:
main(argc, char* argv[]); /* see remark below... */
而不是
int main(int argc, char *argv[]);
编辑:实际上,正如 Aaron 提醒我们的那样,最原始的语法应该类似于
main(argc, argv) char **argv {... }
由于“原型”是后来才引入的。这大约是在每个人都记录了至少 10 个小时来追踪与类型相关的微妙(而不是那么微妙)的错误之后
几个原因:
因为没关系
因为 C 最初没有无符号关键字或无符号整数类型
因为 C 最初没有检查参数类型,甚至没有原型。因此,通常的做法是甚至不声明 int 类型,因为这是默认值。
因为 int 在某种意义上在当时更重要。一切都是一个整数。 C 部分是从一种甚至没有类型的语言演变而来的。每个变量都是一个词,这就是 int 最初的用途。
更新: Jason S 要求提供来源。我认为您可以从在线 The Development of the C Language 的 dmr 的论文中挖掘出所有这些(“无关紧要”除外)。您可能需要在通常的地方查找较早的语言 BCPL 和 B。
因为 C 很老,而且从一开始就是这样设计的。现在改变它为时已晚。
另一个原因可能是无符号类型可能不方便迭代。例如,这个片段向下迭代:
for (size_t i = SIZE - 1; i >= 0; --i)
...
实际上,是一个错误。当 i 在最后一次迭代中达到 0 时,它将直接进入 4294967295(在 32 位机器上)并且循环不会终止。
出于这个原因,我个人发现普通整数更便于迭代。使用整数时,在将 for
循环从向上计数切换到向下计数时,您不必特别小心。
Google C++ Style Guide 建议不要使用 unsigned int
类型,除非您使用实际的位模式。他们的基本原理也适用于 C。快速总结行:
... C 的类型提升方案导致无符号类型的行为与人们预期的不同。 ...不要使用无符号类型。
这可能不是C原作者的想法,但谁知道呢‽
作为警告问题的解决方案,您可以执行以下操作来抑制警告:
const unsigned int uargc = (unsigned int) argc;
c
,我想我会使用两者都可以使用的方法。
由于 Java 中没有无符号类型,因此在未来更容易将 C 程序移植到 Java 是一个有先见之明的设计决定。
我知道这看起来很奇怪:argc
不应该是负数!但是这样看:int
和 unsigned int
都涵盖了您可以接受的值的范围(如果您有 2^31 个命令行参数,那么您就有问题了),并且 int
键入起来更短。
面试难题:如果 C 与 unsigned int argc
一起使用,输入 unsigned
会用掉多少个键盘?
通过将其设置为 int,范围被限制在 1 和 INT_MAX 之间。这通常意味着没有意外的强制转换或别名会因无意的环绕而使其超出范围。它还允许实现将整个负数和 0 范围用于系统特定的场景。
好的,我只是编造的。真正的原因是,这只是最初的 C 语言开发人员之一做出的任意决定,直到现在还没有人真正考虑过它。 :)
只是一个简单的问题:您是否期望超过 231 个(甚至超过 215 个)命令行参数?我怀疑大多数操作系统可以处理这么多。
2^15-1
rm $(find / -mindepth 3)
find -exec
选项命令一次只为 rm
提供一个参数。在对命令行的数量(或总长度)有上限的系统上,前面的 rm
命令可能会失败。
我想它被设计为与 C 兼容,而在 C 时代,人们并不太关心有符号/无符号的正确性。
main(argc, argv) char **argv {... }
旧式函数定义,但见过/使用过main(argc, argv) int argc; char* argv; { ... }