ChatGPT解决这个技术问题 Extra ChatGPT

为什么 argc 是“int”(而不是“unsigned int”)?

为什么命令行参数计数变量(传统上为 argc)是 int 而不是 unsigned int?这有技术原因吗?

在尝试摆脱所有已签名的未签名比较警告时,我总是忽略它,但从不明白为什么会这样。


m
mjv

事实上,原始 C 语言默认情况下任何变量或参数都定义为 int 类型,这可能是另一个因素。换句话说,您可以:

  main(argc, char* argv[]);  /* see remark below... */

而不是

int main(int argc, char *argv[]);

编辑:实际上,正如 Aaron 提醒我们的那样,最原始的语法应该类似于

  main(argc, argv) char **argv {... } 

由于“原型”是后来才引入的。这大约是在每个人都记录了至少 10 个小时来追踪与类型相关的微妙(而不是那么微妙)的错误之后


实际上它本来应该是 `main(argc,argv) char* argv { } 作为内联参数声明,直到 ANSI C 才引入原型(啊 - 过去的美好时光......我很高兴他们走了)
@对,亚伦!我忘了...我们最好在我们暴露年龄之前停下来;-)
@Aaron 没有见过 main(argc, argv) char **argv {... } 旧式函数定义,但见过/使用过 main(argc, argv) int argc; char* argv; { ... }
C
Community

几个原因:

因为没关系

因为 C 最初没有无符号关键字或无符号整数类型

因为 C 最初没有检查参数类型,甚至没有原型。因此,通常的做法是甚至不声明 int 类型,因为这是默认值。

因为 int 在某种意义上在当时更重要。一切都是一个整数。 C 部分是从一种甚至没有类型的语言演变而来的。每个变量都是一个词,这就是 int 最初的用途。

更新: Jason S 要求提供来源。我认为您可以从在线 The Development of the C Languagedmr 的论文中挖掘出所有这些(“无关紧要”除外)。您可能需要在通常的地方查找较早的语言 BCPL 和 B。


r
rlbond

因为 C 很老,而且从一开始就是这样设计的。现在改变它为时已晚。


C老了。它从一开始就是这样设计的。但我不得不不同意最后一句话(虽然还不足以反对)。 ISO 可以很容易地为 main 添加第三个原型定义,而影响很小。事实上,实现者也可以自由地添加其他主要原型——标准中明确提到了这一点。
@paxdiablo 同意,标准可以而且应该[谨慎地]发展和改变。然而,在这种特殊情况下,这个未签名的 argc 事物如何有助于世界和平?
@mjv 更少的人抱怨互联网上不完全正确的事情意味着更少的人抱怨,这意味着世界和平会比以前稍微多一些。
J
John Bode

Here's 用 dmr 自己的话来说的 C 编程语言的历史。它没有明确说明(至少不是从我给出的快速浏览中),但 C 的最早版本不支持无符号类型。 mjv 关于对 int 的隐式键入的观点也是相关的。

编辑

贝尔实验室的链接已经中断了一段时间:here's 指向同一篇论文的替代链接。


你打败了我。是的,我不相信 B(C 的前身)除了 charint 之外什么都没有,并且每个函数都返回一个 int
B没有char。也不是 int 。它是无类型的。字符==int==void*
E
Eli Bendersky

另一个原因可能是无符号类型可能不方便迭代。例如,这个片段向下迭代:

for (size_t i = SIZE - 1; i >= 0; --i)
  ...

实际上,是一个错误。当 i 在最后一次迭代中达到 0 时,它将直接进入 4294967295(在 32 位机器上)并且循环不会终止。

出于这个原因,我个人发现普通整数更便于迭代。使用整数时,在将 for 循环从向上计数切换到向下计数时,您不必特别小心。


这是因为 C++ 缺少适当的 for_each 构造。我多次遇到同样的问题,但如果我可以使用带有适当迭代器的 std 容器,我总是很高兴。
同意,但在 C 循环中是你所拥有的
A
Adam Goode

Google C++ Style Guide 建议不要使用 unsigned int 类型,除非您使用实际的位模式。他们的基本原理也适用于 C。快速总结行:

... C 的类型提升方案导致无符号类型的行为与人们预期的不同。 ...不要使用无符号类型。

这可能不是C原作者的想法,但谁知道呢‽


我不明白谷歌声称无符号类型的行为“出乎意料”(这在上下文中必须意味着,比有符号类型更出人意料)。有符号和无符号类型一起使用时行为不端,一种将提升为另一种的有符号性。因此,类型提升系统会导致所有整数类型“表现得与预期不同”。
同上。什么?位是位,直到您对它们进行简单的算术运算,此时无符号和有符号的每个对于特定应用程序都是完全有效的。
有符号的好处是你总是有一种方法来表示一个无效的值。不过,您确实必须在上面浪费一点。
-1U 在大多数情况下是一个同样有用的“无效值”。例如,实际上没有任何东西的大小等于地址空间的整个大小,减去 1。实际上我喜欢 Jason 的评论。我希望可以对 C 进行的一项更改是消除有符号/无符号类型并用有符号/无符号运算符变体替换它们。可惜...
那个文件是胡说八道。如果您想要由专业人士编写的严肃编码指南,请阅读 MISRA 或 CERT。
G
Greg Hewgill

作为警告问题的解决方案,您可以执行以下操作来抑制警告:

const unsigned int uargc = (unsigned int) argc;

是的,因为问题被标记为 c,我想我会使用两者都可以使用的方法。
R
Rob Walker

由于 Java 中没有无符号类型,因此在未来更容易将 C 程序移植到 Java 是一个有先见之明的设计决定。


你一定不是很了解 c 程序员。如果他们有先见之明,他们肯定会确保移植到 Java 变得更加困难而不是更少;)
@罗布:???我不会称它为“更容易”——这对于做有符号算术的人来说更容易。对于处理无符号算术和位串,Java 真的很痛苦。
J
Jonathan Leffler

main() 的声明是在将无符号类型添加到语言之前定义的 - 请参阅 DMR 的“Primeval C”页面。添加 unsigned 后更改为时已晚。


H
Harold L

我知道这看起来很奇怪:argc 不应该是负数!但是这样看:intunsigned int 都涵盖了您可以接受的值的范围(如果您有 2^31 个命令行参数,那么您就有问题了),并且 int 键入起来更短。

面试难题:如果 C 与 unsigned int argc 一起使用,输入 unsigned 会用掉多少个键盘?


C 可以将它们命名为 int 和 uint,那么它只是一个额外的字符。
很好的答案;)我认为像数百万
@Zan:我一直希望是这样
大多数冗长的语言都是由键盘公司赞助的,这是一个鲜为人知的秘密。
我相信 COBOL 得到了 Caps Lock 和 Shift 键设计师和工匠合并联盟的支持。
P
Paul Hsieh

通过将其设置为 int,范围被限制在 1 和 INT_MAX 之间。这通常意味着没有意外的强制转换或别名会因无意的环绕而使其超出范围。它还允许实现将整个负数和 0 范围用于系统特定的场景。

好的,我只是编造的。真正的原因是,这只是最初的 C 语言开发人员之一做出的任意决定,直到现在还没有人真正考虑过它。 :)


D
David R Tribble

只是一个简单的问题:您是否期望超过 231 个(甚至超过 215 个)命令行参数?我怀疑大多数操作系统可以处理这么多。


int 但必须至少为 2^15-1
这不是我问的原因,但绝对有可能rm $(find / -mindepth 3)
find -exec 选项命令一次只为 rm 提供一个参数。在对命令行的数量(或总长度)有上限的系统上,前面的 rm 命令可能会失败。
@paxdiablo:错误。 C 保证 INT_MAX 至少为 32767。
q
quant_dev

我想它被设计为与 C 兼容,而在 C 时代,人们并不太关心有符号/无符号的正确性。


“C时代”还远未结束。我不会很快停止使用 C。
C 统治的时代已经结束,这就是我的意思。
除了 C 在嵌入式系统中完全占主导地位,并且在发明更好的东西之前将一直保持这种状态。 C++11 和 C++14 修订版确保了 C++ 在嵌入式系统中没有未来,如果有的话。