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

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

问题描述

具体是下面的代码,标记下面的那一行行吗?

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->aint 类型的对象.C11 6.5.6p7

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

7 就[加法运算符]而言,指向不是数组元素的对象的指针的行为与指向长度为数组的第一个元素的指针的行为相同一种以对象的类型作为其元素类型的.

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<的指针/code> 并推进它:

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天全站免登陆