c - 通过结构别名数组

标签 c arrays struct language-lawyer strict-aliasing

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

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

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),

请参阅文档了解“上述”类型是什么,但它们肯定包括对象的有效类型。

它在标记为的部分中:

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

我读到的是(例如)以下定义明确:

#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;
}

这个程序应该输出 80。

我并不是在提倡这是一个好(或非常有用)的想法,我承认我在一定程度上是这样解释的,因为我想不出这还有什么意思,也不相信这是一个毫无意义的句子!

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

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

然而,即使数组大于 sizeof(s),任何访问 sp->y 的尝试都是“全盘皆输”的未定义行为。

我是否可以礼貌地要求人们说出这句话宽恕的内容,而不是平淡地大喊“严格别名 UB 严格别名 UB”,这似乎是这些事情的常态。

最佳答案

这个问题的答案包含在提案中:Fixing the rules for type-based aliasing我们将看到,不幸的是,在 2010 年提出提案时并未得到解决,该提案包含在 Hedquist, Bativa, November 2010 minutes 中。 .因此 C11 不包含对 N1520 的解决方案,因此这是一个悬而未决的问题:

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 打开说(强调我的前进):

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.

适用于这种情况的相关示例是 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;
  }
}

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.

以下讨论和建议的解决方案非常冗长且难以总结,但似乎以删除上述第五点结束并通过调整 6.5 的其他部分解决问题。但如上所述,所涉及的问题无法解决,我没有看到后续提案。

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

关于c - 通过结构别名数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27908626/

相关文章:

c - C中的printf()和puts()有什么区别?

c - 函数调用是如何解决的?

C, 数组中的随机元素打印到终端时变成 '?' 字符

struct - Solidity:在映射中创建包含映射的结构时出现问题

c - 为什么 main() 函数不返回浮点值?

sizeof 的代码?

javascript - 如何从复杂对象数组中获取唯一属性数组

C计算字符串中某个字符出现的次数

c - 如何在 C 中使用 malloc 和 realloc 正确分配结构中的数组?

c - 类型定义/结构声明