使用char未定义的行为访问数组元素?

由于不清楚什么是未定义的行为以及什么不在C中,我想知道使用char访问数组元素是否是未定义的行为。 例如:

char c = 'A'; int a[3000]; printf("%i\n", a[c]); 

我知道实际上字符和整数在某种程度上是可以互换的,但我仍然不确定。

从语法上讲,只要c是整数类型或者可以提升为整数类型, a[c]就是一个有效的表达式。

从C99标准:

6.5.2.1数组下标

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

如果是c的值。 after被提升为int ,在数组的范围内,那么在运行时应该没有问题。

使用char未定义的行为访问数组元素?

它不是未定义的行为。 它的工作原理类似于另一种整数 然而, char的数值可能令人惊讶地是负面的。


charsigned charunsigned char具有相同的范围。 它是实现定义的。

如果提升的索引加上指针导致有效的内存地址,则使用c作为索引是可以的。 细节: char将被提升为int ,或者可能是unsigned

如果c具有负值,则以下可能是一个问题。 在OP的情况下,使用ASCII编码, 'A'的值为65,因此它没有问题,因为0 <= 65 < 3000 。 @Joachim Pileborg

 char c = 'A'; int a[3000] = { 0 }; printf("%i\n", a[c]); // OK other than a[] not initialize in OP's code. 

它几乎可以工作,但要注意非ASCII字符,值> 127

如果char已签名,它将被提升为整数,从而导致访问arrays外部的内存!

这是例如tolower()天真实现中的常见错误

这应该自动转换为int并转到该数组的元素,因此行为不是未定义的。 但是,真的没有理由这样做。 即使你从”(ASCII十进制值32)开始,你也没有使用其他32个值。

我想你可能正在尝试制作一个非常基本的哈希表。 这可以通过结构和一些函数轻松完成; 通常不好的做法是使用除整数类型之外的任何东西(即使char可以转换为int)作为数组下标。

据我所知,我会说它不是未定义的 ,而是定义得很好。 原因是: char可以被提升为一个integer ,这是一种索引数组的有效方法(或更好地说:指针,数组在该表达式中衰减)。 索引与添加基本相同:

 pointer + index // same as &(pointer[index]) or &(index[pointer]) 

并且,引用http://en.cppreference.com/w/cpp/language/implicit_cast (在“数字促销”下):

[..]小整数类型(例如char )的Prvalues可以转换为更大整数类型(例如int )的prvalues。 特别是, 算术运算符不接受小于int类型作为参数 ,[..]

但是,AFAIK编译器会发出警告,因为通常你不使用char作为索引,因此编译器会尝试提供额外的安全网。

简短的回答是:代码片段无法编译。

中间答案是:如果函数定义的一部分,代码具有未定义的行为,因为它访问未初始化的对象。

答案很长:使用正确初始化的数组,它仍然取决于:

  • 在计算数组索引之前,表达式a[c]中的a[c]将被提升为int ,而C标准要求'A'具有正值,无论char类型是有符号还是无符号。 如果char类型有8位,则行为不会被定义,但是定义为'A'的实际值的实现取决于目标体系结构。

  • 如果char类型大于11位,则值'A'可能超过3000 ,因此表达式尝试访问超出数组末尾的访问,该数组具有未定义的行为。