是否可以通过成员地址访问超过结构大小的空间并分配足够的空间? [英] Is it OK to access past the size of a structure via member address, with enough space allocated?

查看:111
本文介绍了是否可以通过成员地址访问超过结构大小的空间并分配足够的空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体来说,下面的代码是标记下方的行吗?

Specifically, is the following code, the line below the marker, OK?

struct S{
    int a;
};

#include <stdlib.h>

int main(){
    struct S *p;
    p = malloc(sizeof(struct S) + 1000);
    // This line:
    *(&(p->a) + 1) = 0;
}

人们在此处提出了争论,但是没有人给出令人信服的解释或参考.

People have argued here, but no one has given a convincing explanation or reference.

他们的论点稍有不同,但本质上是相同的

Their arguments are on a slightly different base, yet essentially the same

typedef struct _pack{
    int64_t c;
} pack;

int main(){
    pack *p;
    char str[9] = "aaaaaaaa"; // Input
    size_t len = offsetof(pack, c) + (strlen(str) + 1);
    p = malloc(len);
    // This line, with similar intention:
    strcpy((char*)&(p->c), str);
//                ^^^^^^^

推荐答案

至少自1989年C标准化以来,其目的一直是允许检查数组边界以实现数组访问.

The intent at least since the standardization of C in 1989 has been that implementations are allowed to check array bounds for array accesses.

成员p->a是类型int的对象. C11 6.5.6p7 表示

The member p->a is an object of type int. C11 6.5.6p7 says that

7就 [additive operator] 而言,指向不是数组元素的对象的指针的行为与指向length数组的第一个元素的指针的行为相同一种以对象的类型为其元素类型.

7 For the purposes of [additive operators] a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

因此

&(p->a)

是指向int的指针;但是它好像是一个指向长度为1的数组的第一个元素的指针,对象类型为int.

is a pointer to an int; but it is also as if it were a pointer to the first element of an array of length 1, with int as the object type.

现在 6.5.6p8 允许人们计算&(p->a) + 1是指向数组末尾的指针,因此没有未定义的行为.但是,这样的指针的取消引用是无效的.在附录J.2 中,行为在以下情况下未定义:

Now 6.5.6p8 allows one to calculate &(p->a) + 1 which is a pointer to just past the end of the array, so there is no undefined behaviour. However, the dereference of such a pointer is invalid. From Appendix J.2 where it is spelt out, the behaviour is undefined when:

在数组对象和整数类型之内或之外直接添加或减去一个指针所产生的结果指向数组对象正好超出数组对象的位置,并用作评估的一元*运算符的操作数(6.5 .6).

Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond the array object and is used as the operand of a unary * operator that is evaluated (6.5.6).

在上面的表达式中,只有一个数组,其中一个(好像)只有1个元素.如果取消引用&(p->a) + 1,则超出范围的长度为1的数组将被访问,并且

In the expression above, there is only one array, the one (as if) with exactly 1 element. If &(p->a) + 1 is dereferenced, the array with length 1 is accessed out of bounds and undefined behaviour occurs, i.e.

[C11]标准对此行为没有要求的行为[...]

behavior [...], for which [The C11] Standard imposes no requirements

使用注意说:

可能的不确定行为包括完全忽略情况并导致无法预测的结果,到翻译或程序执行期间以环境特征记录的方式表现(有无诊断消息),终止翻译或执行(伴随发出诊断消息).

Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

最常见的行为是完全忽略情况,即行为就像指针在紧随其后引用了内存位置一样,并不意味着其他行为就不会被接受.标准的观点-该标准可以实现所有可以想象和无法想象的结果.

That the most common behaviour is ignoring the situation completely, i.e. behaving as if the pointer referenced the memory location just after, doesn't mean that other kind of behaviour wouldn't be acceptable from the standard's point of view - the standard allows every imaginable and unimaginable outcome.

有人声称,C11标准文本的文字含糊不清,委员会的意图应该是确实允许这样做,而且以前也没关系.这不是真的.阅读委员会对[1992年12月10日对 C89 的缺陷报告#017"的答复部分.

There has been claims that the C11 standard text has been written vaguely, and the intention of the committee should be that this indeed be allowed, and previously it would have been alright. It is not true. Read the part from the committee response to [Defect Report #017 dated 10 Dec 1992 to C89].

问题16

[...]

回复

对于数组数组,允许使用的指针算法 第6.3.6节,第47页,第12-40行应理解为 将 object 一词的使用解释为表示特定 直接由指针的类型和值确定的对象,而不由其他对象确定 通过连续性与该对象相关的对象.因此,如果一个表达式 超出这些权限,则行为是不确定的.例如, 以下代码具有未定义的行为:

For an array of arrays, the permitted pointer arithmetic in subclause 6.3.6, page 47, lines 12-40 is to be understood by interpreting the use of the word object as denoting the specific object determined directly by the pointer's type and value, not other objects related to that one by contiguity. Therefore, if an expression exceeds these permissions, the behavior is undefined. For example, the following code has undefined behavior:

 int a[4][5];

 a[1][7] = 0; /* undefined */ 

一些符合要求的实现 选择诊断数组界限冲突,而其他人可能会 选择使用来成功解释此类尝试访问 显而易见扩展语义.

Some conforming implementations may choose to diagnose an array bounds violation, while others may choose to interpret such attempted accesses successfully with the obvious extended semantics.

(强化重点)

没有理由不会将相同的 传递给结构的标量成员,尤其是在6.5.6p7指出指向它们的指针的行为应与相同时.一个指向长度为1的数组的第一个元素的指针,该对象的类型为其元素类型.

There is no reason why the same wouldn't be transferred to scalar members of structures, especially when 6.5.6p7 says that a pointer to them should be considered to behave the same as a pointer to the first element of an array of length one with the type of the object as its element type.

如果要寻址连续的struct,则始终可以将指针指向第一个成员,并将其转换为指向struct的指针,然后将其前进:

If you want to address the consecutive structs, you can always take the pointer to the first member and cast that as the pointer to the struct and advance that instead:

*(int *)((S *)&(p->a) + 1) = 0;

这篇关于是否可以通过成员地址访问超过结构大小的空间并分配足够的空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆