这个问题可能有点争议。
我在块范围内有以下代码:
int *a = malloc(3 * sizeof(int));
if (!a) { ... error handling ... }
a[0] = 0;
a[1] = 1;
a[2] = 2;
我认为这段代码调用了UB由于指针算术超出范围。
原因是,有效型对象指针的a
从来没有
设置int[3]
反而int
仅有的。因此,对索引处的对象的任何访问
C 标准没有定义 0 以外的值。
原因如下:
Line a = malloc(...)
。
如果分配成功则a
足以存储 3 个区域的点int
s.
a[0] = ...
相当于*a = ...
,l 值为int
。它设置了有效型第一个的sizeof(int)
字节到int
如规则所示6.5p6.
...对于对没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型。
现在指针a
指向类型的对象int
, not int[3]
.
a[1] = ...
相当于*(a + 1) =
。表达a + 1
指向末尾后一个元素int
对象可通过*a
。
该指针本身对于比较有效,但访问未定义,因为:
Rule 6.5.6p7:
...指向不是数组元素的对象的指针的行为与指向长度为 1 的数组的第一个元素的指针相同,对象的类型作为其元素类型。
并统治6.5.6p8:
...如果结果指向数组对象的最后一个元素,则不应将其用作所计算的一元 * 运算符的操作数。
类似的问题与相关a[2] = ...
但这里甚至a + 2
隐藏在a[2]
调用UB.
如果标准允许在有效内存区域进行任意指针算术,只要满足对齐要求和严格的别名规则,这个问题就可以得到解决。或者相同类型的连续对象的任何集合都可以视为数组。然而,我没能找到这样的东西。
如果我对标准的解释是正确的,那么某些 C 代码(全部?)将是未定义的。
因此,当我希望我能做到这一点时,这是罕见的情况之一wrong.
Am I?