[英]Allocating less memory than the specified size of a pointer-to-array
在 C 中,如果我们只访问属于已分配内存的元素,那么将内存分配不足给数组指针是否“合法”? 或者这是否会调用未定义的行为?
int (*foo)[ 10 ]; //Pointer to array of 10 ints
foo = malloc( sizeof( int ) * 5 ); //Under-allocation! Only enough memory for 5 ints
//Now we only ever access (*foo)[ 0 - 4 ]
如果这本身不是未定义的行为,那么访问另一个不相关的对象,其内存地址恰好落在数组未分配部分的地址空间内会导致严格别名违规吗?
这是未定义的行为。
foo
应该指向int[10]
类型的对象(或对象数组中的第一个)。 您没有分配那么多空间,因此类型为int[10]
的表达式*foo
访问该类型的对象,但这样做会读取已分配内存段的末尾。
正如@dbush 在他的回答中所描述的,一个数组被定义为元素类型(C17 6.2.5/20)的一组连续分配的非空对象。 显然, malloc( sizeof( int ) * 5 )
没有为int[10]
分配足够的空间。
但是我发现很难正式支持该答案的最后一部分,声称大小差异使(例如) (*foo)[4]
具有未定义的行为。 这个结论似乎是有道理的,但标准实际上在哪里这么说的?
这里的主要问题之一是(动态)分配的对象没有声明类型,只有在某些情况下,有效类型取决于它们的访问方式和访问方式。 (C17 6.5/6 和脚注 88)。 我们确实知道,如果成功, malloc(n)
返回一个指向大小为n
的对象的指针(C17 7.22.3.4/2),但是我们如何将未定义的行为具体归因于与描述对象的有效类型的对象的关联?尺寸大于n
?
我最终决定连接点的最佳方法如下。 假设o
是大小为n
已分配对象, T
是sizeof(T) > n
的完整类型,并且o
是通过T
类型的左值读取或写入的。 然后第 6.5/6 段将有效类型T
归因于对象o
,但由于o
的大小不足,我们必须得出结论,它的表示构成了类型T
(C17 3.19.4) 的陷阱表示。 然后第 6.2.6.1/5 段重申了“陷阱表示”的定义,并让我们到达了我们想要去的地方:
某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示形式并且被没有字符类型的左值表达式读取,则行为未定义。 如果这种表示是由没有字符类型的左值表达式修改对象的全部或任何部分的副作用产生的,则行为是未定义的。 这种表示称为陷阱表示。
(加了重点。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.