C中数组索引的正确类型是什么?

Mic*_*has 40 c indexing types c99

应该使用C99中的数组索引的类型?它必须适用于LP32,ILP32,ILP64,LP64,LLP64等.它不一定是C89类型.

我找到了5位候选人:

  • size_t
  • ptrdiff_t
  • intptr_t/uintptr_t
  • int_fast*_t/uint_fast*_t
  • int_least*_t/uint_least*_t

有一个简单的代码可以更好地说明问题.什么是最好的类型i,并j在这两个特定的循环.如果有充分的理由,两种不同的类型也可以.

for (i=0; i<imax; i++) {
        do_something(a[i]);
}
/* jmin can be less than 0 */
for (j=jmin; j<jmax; j++) {
        do_something(a[j]);
}
Run Code Online (Sandbox Code Playgroud)

PS在问题的第一个版本中,我忘记了负面索引.

PPS我不打算编写C99编译器.但是编译器程序员的任何答案对我来说都是非常有价值的.

类似的问题:

Joh*_*itb 37

我认为你应该使用ptrdiff_t以下原因

  • 指数可能是负数(因此所有无符号类型,包括size_t,都是不可能的)
  • 类型p2 - p1ptrdiff_t.该类型i == p2 - p1的反向的事情,p2应该是那种太(请注意,p2 == p1 + i是等同于*(p + i))

  • @unwind,肯定为什么不呢?`int a [10]; int*pa = a + 1; pa [-1] = 0;`.数组索引只不过是指针算术,而C并不关心你给出的值.对于许多完全合法的索引操作,使用无符号索引类型将失败. (12认同)
  • 似乎PTRDIFF_MAX可能小于SIZE_MAX,因此对于大型阵列可能会失败:http://stackoverflow.com/a/31090426/895245`p1 + i`不是指针差异:它是指针+ int. (4认同)
  • “指数可能为负”是什么意思?不是在实际索引时,确定吗? (2认同)
  • 对于前哨值小于零的情况也很有用。但实际上,如果发问者的目标类型适用于所有情况,那么用例就无关紧要。重要的是实际上,无符号类型是错误的选择。 (2认同)

R..*_*R.. 25

我几乎总是size_t用于数组索引/循环计数器.当然,在某些特殊情况下您可能需要签名偏移,但通常使用签名类型会遇到很多问题:

最大的风险是,如果你通过调用者传递一个巨大的大小/偏移量来处理未签名的东西(或者如果你从一个错误信任的文件中读取它),你可能会把它解释为一个负数并且不能理解它是出界.例如,if (offset<size) array[offset]=foo; else error();它会写在不应该的地方.

另一个问题是带有符号整数溢出的未定义行为的可能性.无论你是使用无符号算术还是有符号算术,都需要注意和检查溢出问题,但我个人觉得无符号行为更易于处理.

使用无符号算术的另一个原因(通常) - 有时我使用索引作为位数的偏移量,我想使用%8和/ 8或%32和/ 32.对于签名类型,这些将是实际的除法操作.使用无符号时,可以生成预期的按位和/位移操作.

  • 正确的类型是(有符号)int。索引可以为负数。 (2认同)
  • @EnzoR:“int”绝对是不正确的。索引可以大于“INT_MAX”。如果您需要索引的有符号类型(用于相对于指向数组的第一个元素之外的其他位置的指针),则它是“ptrdiff_t”,而不是“int”。 (2认同)
  • @Enzo_R - 您需要一个有符号整数类型,但不是“int”。在大多数现代 64 位平台上,int 是一个 32 位值,不足以表示 64 位平台上数组的可能索引。仅仅因为示例使用“int”并不意味着它实际上是最好的类型。前面的评论已经引用了标准的一个功能 ptrdiff_t,这是一个比 int 更好的答案,因为它是一个有符号整数类型,会自动调整大小为平台的指针大小。 (2认同)

Amn*_*non 13

由于sizeof(array)(和malloc's参数)的类型是size_t,并且数组不能容纳比其大小更多的元素,因此size_t可以用于数组的索引.

编辑 此分析适用于基于0的数组,这是常见的情况.ptrdiff_t在任何情况下都可以工作,但索引变量有一个指针差异类型有点奇怪.

  • @Chris:我没有说sizeof(数组)是元素的数量. (9认同)
  • 这不太正确.sizeof(array)以字节为单位计算数组的大小,*不是*元素的数量.ISO/IEC 9899:TC3§6.5.3.4.6 (3认同)

Cir*_*四事件 9

如果你开始size_t使用size_t,因为该类型必须能够索引任何数组:

  • 0返回它,因此对于具有多个size_t元素的数组无效
  • sizeof 正如Amnon所提到的那样把它作为论据

如果你从零开始,然后转移到零开始,并使用size_t,由于上述原因,保证可以工作.所以替换:

for (j = jmin; j < jmax; j++) {
    do_something(a[j]);
}
Run Code Online (Sandbox Code Playgroud)

有:

int *b = &a[jmin];
for (size_t i = 0; i < (jmax - jmin); i++) {
    do_something(b[i]);
}
Run Code Online (Sandbox Code Playgroud)

为什么使用:

  • ptrdiff_t:此表示的最大值可能小于最大值malloc.

    在cppref中提到,如果数组太大,可能会出现未定义的行为,建议在C99 6.5.5/9:

    当减去两个指针时,两个指针都指向同一个数组对象的元素,或者指向数组对象的最后一个元素的元素; 结果是两个数组元素的下标的差异.结果的大小是实现定义的,其类型(有符号整数类型)是标头中定义的ptrdiff_t. 如果结果在该类型的对象中无法表示,则行为未定义.

    出于好奇,size_t也可能size_t比分段内存架构更大:https://stackoverflow.com/a/1464194/895245

    GCC还对静态数组对象的最大大小施加了进一步的限制:C中数组的最大大小是多少?

  • uintptr_t:我不确定.所以我只是使用intptr_t因为我更确定:-)


use*_*067 5

我的选择:ptrdiff_t

许多人投票支持ptrdiff_t,但有些人表示使用指针差异类型进行索引很奇怪。对我来说,这是完全有道理的:数组索引是与原点指针的差值。

有些人还说这size_t是正确的,因为它是为了容纳尺寸而设计的。然而,正如一些人评论的那样:这是以字节为单位的大小,因此通常可以容纳比最大可能数组索引大几倍的值。