数组的索引和argc签名

时间:2010-03-14 14:08:59

标签: c arrays unsigned signed

C standard 5.1.2.2.1程序启动)说:

  

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

     

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

后来说:

  

argc的值应为非负值。

  • 为什么不应该 argc被定义为unsigned intargc被认为是'参数计数'?
  • argc
  • 应该argv用作索引吗?

所以我开始想知道C标准是否说明了数组索引的类型。签了吗?

6.5.2.1数组下标

  

其中一个表达式应具有类型   ''指向对象类型的指针'',另一个   表达式应具有整数类型,   结果的类型为'' type ''。

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

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

4 个答案:

答案 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,因为argcint的签名类型,即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运行时实现,出于历史原因,您可以通过运行时传递环境变量。