C标准 (5.1.2.2.1 程序启动)说:

在程序启动时调用的函数被命名为主。 [...]
它应使用返回类型的INT定义,没有参数:
int main(void) { /* ... */ }

或有两个参数 [...] :
int main(int argc, char *argv[]) { /* ... */ }

后来又说:

argc 的值应为非负数。

  • 为什么 不应该 argc 被定义为 unsigned int, argc 据说意思是“参数计数”?
  • 应该 argc 用作索引 argv?

所以我开始想知道 C 标准是否规定了有关数组索引类型的内容。签了吗?

6.5.2.1 数组下标:

其中一种表达式应具有“类型”指向对象类型的指针'',另一个表达 整数类型,结果具有类型'类型’’.

它没有说明它的签名(或者我没有找到它)。使用负数数组索引的代码很常见(array[-1])但这不是未定义的行为吗?

  • 数组的索引应该是无符号的吗?
有帮助吗?

解决方案

main() 中 int 的原因是历史性的 - 早在语言标准化之前就一直如此。数组索引的要求是它位于数组的范围内(或者在某些情况下,超出数组末尾) - 其他任何内容都是未定义的,因此符号性并不重要。

其他提示

1)关于main() argc类型:恕我直言,该标准延续了一个非常古老的传统(超过 30 年!),现在......现在改变一切已经太晚了(注意:在大多数系统上,如果“argc”被定义为“无符号”,编译器、链接器和CPU都不会抱怨,但你超出了标准!)

2) 在大多数实现中,argv[argc] 是合法的并且计算结果为 NULL。事实上,找到参数列表末尾的另一种方法是从 0 开始迭代 argv,当 argv[i] 为 NULL 时终止。

3) 只要从 (p-n) 到 p 的地址范围属于同一个内存对象,负数的数组/指针运算是合法的。IE。你可以有

char array[100];
char *p;

p = &array[50];
p += -30; /* Now p points to array[20]. */

指针算术的这种用法是合法的,因为结果指针仍然保留在原始内存对象(“数组”)内。在大多数系统上,指针算术可用于在内存中导航,这违反了此规则,但这不是可移植的,因为它完全依赖于系统。

一般来说,在 C 语言中,“最小意外原则”意味着最好使变量带符号,除非有充分的理由不带符号。这是因为当您混合有符号和无符号值时,类型提升规则可能会导致意外结果:例如,如果 argc 未签名,那么这个简单的比较将导致令人惊讶的结果:

if (argc > -1)

(这 -1 被提升为 unsigned int, ,所以它的值被转换为 UINT_MAX, ,这几乎肯定大于 argc).

1) Argc 是一个参数计数,但是说实话,你怎么能在程序名称之前添加一个参数呢? argv[0]. 。想象一个名为 foo, ,你不能简单地说 args1 foo args2 因为这毫无意义,尽管 argc 是有符号类型 int, , IE。没有这样的事情 argv[-1] 这会让你得到“args1”...

2) argc 并不是真正参数向量的索引(因此 '精液')作为运行时将可执行程序名称填充到第零个偏移量中,即 argv[0] 因此 argc 将关闭 1。

3)数组索引,就指针操作而言, 假如 您位于指针所在内存块的边界内,使用数组下标作为负数是合法的,因为数组下标是指针的快捷方式,不仅如此,它们是可交换的,例如

char v[100];
char *p = &v[0];

You can do this:

p[55] = 'a'; 

Which is the same as

*(p + 55) = 'a';

You can even do this:

p = &v[55];

p[-10] = 'b' /* This will stuff 'b' into 45'th offset! */

Which is the same as

*(p - 10) = 'b';

此外,如果您以超出边界的方式使用和操作数组 - 这是未定义的行为,并且将取决于运行时的实现如何处理它,可能是分段错误或程序崩溃。 ..

4) 在 *nix 环境中,有些环境会向 main 提供第三个参数 char **endvp, ,同样,这在 Microsoft 的 DOS/Windows 世界中很少使用。某些 *nix 运行时实现,出于史前原因,您可以通过运行时传入环境变量。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top