通过结构别名数组 [英] Aliasing Arrays through structs

查看:32
本文介绍了通过结构别名数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读 ISO/IEC 9899:TC2 中 6.5 的第 7 段.

它允许通过以下方式对对象进行左值访问:

<块引用>

包含上述之一的聚合或联合类型其成员之间的类型(包括递归地,子聚合或包含联合),

请参考文档了解上述"类型是什么,但它们肯定包括对象的有效类型.

它在一个注释为:

<块引用>

此列表的目的是指定在哪些情况下对象可能有别名也可能没有别名.

我认为(例如)以下内容是明确定义的:

#include #include 类型定义结构{无符号整数 x;} s;int main(void){无符号整数数组[3] = {73,74,75};s* sp=(s*)&array;sp->x=80;printf("%d\n",array[0]);返回退出成功;}

这个程序应该输出 80.

我不是在提倡这是一个好(或非常有用)的想法,我承认我部分是这样解释的,因为我想不出这意味着什么,也不敢相信这是一个毫无意义的句子!

也就是说,我看不出有什么很好的理由来禁止它.我们所知道的是该位置的对齐和内存内容与 sp->x 兼容,为什么不呢?

似乎可以说如果我在结构的末尾添加(比如说)一个 double y; 我仍然可以访问 array[0]以这种方式通过sp->x.

然而,即使数组大于 sizeof(s),任何访问 sp->y 的尝试都是完全赌注"未定义行为.

我是否可以礼貌地要求人们说出这句话所宽恕的内容,而不是大喊严格别名 UB 严格别名 UB",因为这些事情似乎太常见了.

解决方案

这个问题的答案包含在提案中:修复基于类型的别名的规则,我们将看到,遗憾的是在 2010 年提出提案时没有得到解决,该提案包含在 赫奎斯特,巴蒂瓦,2010 年 11 月 分钟.因此 C11 不包含对 N1520 的解析,所以这是一个悬而未决的问题:

<块引用>

这件事似乎没有任何办法本次会议解决.建议方法的每个线程导致更多问题.1 2010 年 11 月 4 日星期四上午 1:48.

行动 - 克拉克做更多的工作

N1520 开头说(强调我的未来):

<块引用>

Richard Hansen 指出了基于类型别名的一个问题规则如下:

我的问题涉及 6.5p7 中第 5 项的措辞(别名适用于联合/聚合).除非我的理解有效类型不正确,似乎是联合/聚合条件应该应用于有效类型,而不是左值类型.

以下是更多详细信息:

以下代码片段为例:

union {int a;双 b;} u;u.a = 5;

根据我对有效类型定义(6.5p6)的理解,位置&u处的对象的有效类型是union {int a;双 b;}.访问的左值表达式的类型&u 中的对象(在第二行)是 int.

根据我对兼容类型定义(6.2.7)的理解,int与union {int a;不兼容;双 b;},所以6.5p7 的第 1 条和第 2 条不适用.int 不是签名或联合类型的无符号类型,因此第 3 条和第 4 条不适用.整数不是字符类型,因此第 6 条不适用.

剩下第 5 项.但是,int 不是聚合或联合类型,因此项目符号也不适用.也就是说上面的代码违反了别名规则,这显然不应该.

我认为应该改写第 5 条,以表明如果有效类型(不是左值类型)是聚合或联合类型包含类型与左值类型兼容的成员,然后对象可以被访问.

实际上,他指出的是规则是不对称的关于结构/工会成员资格.我已经意识到这一点情况,并认为这是一个(非紧急的)问题,在相当长的一段时间内时间.一系列的例子会更好地说明问题.(这些示例最初是在圣克鲁斯会议上提出的.)

根据我关于别名是否有效的问题的经验在类型约束上,这个问题总是被表述为循环不变性.这样的例子使问题变得极其尖锐重点.

适用于这种情况的相关示例是 3,如下所示:

<块引用>

struct S { int a, b;};void f3(int *pi, struct S *ps1, struct S const *ps2){for (*pi = 0; *pi <10; ++*pi) {*ps1++ = *ps2;}}

这里的问题是对象*ps2是否可以被访问(并且特别修改)通过分配给左值 *pi - 如果是这样,标准是否真的这么说.可以说这是未包含在 6.5p7 的第五个项目符号中,因为 *pi 没有聚合类型.

**或许本意是要反过来问:是它允许通过左值 ps2 访问对象 pi 的值.显然,这种情况将包含在第五项中.

关于这种解释,我只能说它从来没有想过在圣克鲁斯会议之前,我是一个可能性,即使我已经在整个过程中对这些规则进行了相当深入的思考很多年.即使这种情况可能被认为是由现有的措辞,我建议可能值得寻找一个不透明的配方.

以下讨论和提议的解决方案很长且难以总结,但似乎以删除上述第 5 项并通过调整 6.5 的其他部分来解决问题而告终.但如上所述,所涉及的问题无法解决,我也没有看到后续提案.

因此,标准措辞似乎允许 OP 演示的场景,尽管我的理解是这是无意的,因此我会避免它,并且它可能会在以后的标准中更改为不符合要求.

I'm reading paragraph 7 of 6.5 in ISO/IEC 9899:TC2.

It condones lvalue access to an object through:

an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union),

Please refer to the document for what 'aforementioned' types are but they certainly include the effective type of the object.

It is in a section noted as:

The intent of this list is to specify those circumstances in which an object may or may not be aliased.

I read this as saying (for example) that the following is well defined:

#include <stdlib.h>
#include <stdio.h>

typedef struct {
    unsigned int x;
} s;

int main(void){
    unsigned int array[3] = {73,74,75};

   s* sp=(s*)&array; 

   sp->x=80;

   printf("%d\n",array[0]);

   return EXIT_SUCCESS;
}

This program should output 80.

I'm not advocating this as a good (or very useful) idea and concede I'm in part interpreting it that way because I can't think what else that means and can't believe it's a meaningless sentence!

That said, I can't see a very good reason to forbid it. What we do know is that the alignment and memory contents at that location are compatible with sp->x so why not?

It seems to go so far as to say if I add (say) a double y; to the end of the struct I can still access array[0] through sp->x in this way.

However even if the array is larger than sizeof(s) any attempt to access sp->y is 'all bets off' undefined behaviour.

Might I politely ask for people to say what that sentence condones rather than go into a flat spin shouting 'strict aliasing UB strict aliasing UB' as seems to be all too often the way of these things.

解决方案

The answer to this question is covered in proposal: Fixing the rules for type-based aliasing which we will see, unfortunately was not resolved in 2010 when the proposal was made which is covered in Hedquist, Bativa, November 2010 minutes . Therefore C11 does not contain a resolution to N1520, so this is an open issue:

There does not seem to be any way that this matter will be resolved at this meeting. Each thread of proposed approaches leads to more questions. 1 1:48 am, Thurs, Nov 4, 2010.

ACTION – Clark do more work in

N1520 opens saying (emphasis mine going forward):

Richard Hansen pointed out a problem in the type-based aliasing rules, as follows:

My question concerns the phrasing of bullet 5 of 6.5p7 (aliasing as it applies to unions/aggregates). Unless my understanding of effective type is incorrect, it seems like the union/aggregate condition should apply to the effective type, not the lvalue type.

Here are some more details:

Take the following code snippet as an example:

union {int a; double b;} u;
u.a = 5;

From my understanding of the definition of effective type (6.5p6), the effective type of the object at location &u is union {int a; double b;}. The type of the lvalue expression that is accessing the object at &u (in the second line) is int.

From my understanding of the definition of compatible type (6.2.7), int is not compatible with union {int a; double b;}, so bullets 1 and 2 of 6.5p7 do not apply. int is not the signed or unsigned type of the union type, so bullets 3 and 4 do not apply. int is not a character type, so bullet 6 does not apply.

That leaves bullet 5. However, int is not an aggregate or union type, so that bullet also does not apply. That means that the above code violates the aliasing rule, which it obviously should not.

I believe that bullet 5 should be rephrased to indicate that if the effective type (not the lvalue type) is an aggregate or union type that contains a member with type compatible with the lvalue type, then the object may be accessed.

Effectively, what he points out is that the rules are asymmetrical with respect to struct/union membership. I have been aware of this situation, and considered it a (non-urgent) problem, for quite some time. A series of examples will better illustrate the problem. (These examples were originally presented at the Santa Cruz meeting.)

In my experience with questions about whether aliasing is valid based on type constraints, the question is invariably phrased in terms of loop invariance. Such examples bring the problem into extremely sharp focus.

And the relevant example that applies to this situation would be 3 which is as follows:

struct S { int a, b; };
void f3(int *pi, struct S *ps1, struct S const *ps2)
{
  for (*pi = 0; *pi < 10; ++*pi) {
      *ps1++ = *ps2;
  }
}

The question here is whether the object *ps2 may be accessed (and especially modified) by assigning to the lvalue *pi — and if so, whether the standard actually says so. It could be argued that this is not covered by the fifth bullet of 6.5p7, since *pi does not have aggregate type at all.

**Perhaps the intention is that the question should be turned around: is it allowed to access the value of the object pi by the lvalue ps2. Obviously, this case would be covered by the fifth bullet.

All I can say about this interpretation is that it never occurred to me as a possibility until the Santa Cruz meeting, even though I've thought about these rules in considerable depth over the course of many years. Even if this case might be considered to be covered by the existing wording, I'd suggest that it might be worth looking for a less opaque formulation.

The following discussion and proposed solutions are very long and hard to summarize but seems to end with a removal of the aforementioned bullet five and resolve the issue with adjustments to other parts of 6.5. But as noted above this issues involved were not resolvable and I don't see a follow-up proposal.

So it would seem the standard wording permits the scenario the OP demonstrates although my understanding is that this was unintentional and therefore I would avoid it and it could potentially change in later standards to be non-conforming.

这篇关于通过结构别名数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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