是无符号字符[4] [5]; 一个[1] [7]; 未定义的行为?

R..*_*R.. 9 c arrays strict-aliasing undefined-behavior

来自C标准的未定义行为的示例之一(J.2):

- 数组下标超出范围,即使一个对象显然可以使用给定的下标访问(如左边的表达式a [1] [7],给出声明int a [4] [5])(6.5.6)

如果声明从更改int a[4][5]unsigned char a[4][5],访问a[1][7]仍会导致未定义的行为吗?我的意见是,它没有,但我从其他人那里听到了不同意见,我想看看其他一些想成为专家的想法.

我的推理:

  • 根据6.2.6.1第4段和第6.5段第7段的通常解释,对象的表示asizeof (unsigned char [4][5])*CHAR_BIT位,可以作为unsigned char [20]与对象重叠的类型数组进行访问.

  • a[1]将type unsigned char [5]作为左值,但在表达式中使用(作为运算[]符的操作数,或等效地作为运算+符的操作数*(a[1]+7)),它衰减为类型的指针unsigned char *.

  • a[1]也是指向a表单中"表示"的字节的指针unsigned char [20].以这种方式解释,添加7 a[1]是有效的.

Alc*_*ive -1

我认为引用的(J.2)示例是未定义行为的原因是链接器不需要将子数组 a[1]、a[2] 等彼此相邻地放置在内存中。它们可能分散在内存中,也可能相邻但不按预期顺序。将基本类型从 int 切换为 unsigned char 不会改变这一切。

  • 不,它们在内存中肯定是相邻的。想想“sizeof”和“memcpy”是如何工作的。据我所知,原因与别名有关。您希望编译器能够假设“a[0][i]”和“a[1][j]”永远不会指向同一位置。但所有的赌注都取决于角色类型。指向字符类型的指针始终可以为其他指针(指向任何类型)起别名,除非使用“restrict”关键字告诉编译器它不会这样做。 (2认同)