C standard( 5.1.2.2.1程序启动)说:
程序启动时调用的函数 被命名为主要。 [...]
它应该用a定义 返回int类型和没有 参数:
的int main(void) { /* ... */ }
或带有两个参数 [...] :
的int main(int argc, char *argv[]) { /* ... */ }
后来说:
argc的值应为非负值。
argc
被定义为unsigned int
,argc
被认为是'参数计数'?argc
argv
用作索引吗?
所以我开始想知道C标准是否说明了数组索引的类型。签了吗?
6.5.2.1数组下标:
其中一个表达式应具有类型 ''指向对象类型的指针'',另一个 表达式应具有整数类型, 结果的类型为'' type ''。
它没有说明它的签名(或者我没有找到它)。看到使用负数组索引(array[-1]
)的代码很常见,但是它不是未定义的行为吗?
答案 0 :(得分:6)
main()中int的原因是历史性的 - 它始终是这样的,因为早在语言标准化之前。数组索引的要求是它在数组的范围内(或者在某些情况下,结束时) - 其他任何未定义的内容,因此签名是无关紧要的。
答案 1 :(得分:3)
1)关于main()argc类型:恕我直言,标准延续了一个非常古老的传统(超过30年!),现在......改变事情已经太晚了(注意:在大多数系统上都没有编译器,如果“argc”被定义为“unsigned”,也不会出现链接器,CPU也不会抱怨,但是你不符合标准!)
2)在大多数实现中,argv [argc]是合法的并且求值为NULL。实际上,找到参数列表末尾的另一种方法是在argv [i]为NULL时从0终止argv。
3)具有负数的数组/指针算法是合法的,只要从(p-n)到p的地址范围属于同一个存储器对象。 I.E.你可以
char array[100];
char *p;
p = &array[50];
p += -30; /* Now p points to array[20]. */
这种指针运算的使用是合法的,因为结果指针仍然保留在原始内存对象(“数组”)内。在大多数系统中,指针算法可以用于在内存中导航而违反此规则,但这不是可移植的,因为它完全取决于系统。
答案 2 :(得分:3)
一般来说,在C中,“最小意外原则”意味着最好使变量签名,除非有充分的理由使其无符号。这是因为当您混合使用有符号值和无符号值时,类型提升规则会导致意外结果:例如,如果argc
未签名,则此简单比较会导致令人惊讶的结果:
if (argc > -1)
(-1
被提升为unsigned int
,因此其值会转换为UINT_MAX
,几乎肯定会大于argc
。
答案 3 :(得分:-2)
1)Argc是一个参数计数,但说实话,你怎么能在程序名argv[0]
之前加一个参数。想象一个名为foo
的程序,你不能简单地说args1 foo args2
,因为argc
是int
的签名类型,即argv[-1]
没有意义,这是无意义的。这会让你'args1'...
2)argc实际上不是参数向量的索引(因此' argv '),因为运行时将可执行程序名称填充到第零个偏移量,即{{ 1}}因此argv[0]
将被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环境中,有些人会将第三个参数提供给主argc
,这在DOS / Windows的Microsoft世界中很少使用。一些* nix运行时实现,出于历史原因,您可以通过运行时传递环境变量。