这是严格的别名违规吗?

时间:2017-10-23 10:13:09

标签: c strict-aliasing

struct __packed element {
    char val;
};

void foo(struct element arr[4], uint32_t a) {
    uint32_t* i = (uint32_t*)arr;
    *i = a;
}

int main(void) {
    struct element arr[4] __aligned(4);

    foo(arr, 5);
    ...
}

就像标题一样,这是否是C中严格的别名冲突?

假设arr的存储类型为struct element[4]

2 个答案:

答案 0 :(得分:5)

是的,此(*i = a)是严格的别名违规。

N1570§6.5p7:

  

对象的存储值只能由具有其中一个的左值表达式访问   以下类型:88)

     
      
  • 与对象的有效类型兼容的类型
  •   
  • 与对象的有效类型兼容的类型的限定版本,
  •   
  • 对应于有效类型的有符号或无符号类型的类型   对象,
  •   
  • 对应于合格版本的有符号或无符号类型的类型   有效的对象类型,
  •   
  • 聚合或联合类型,其中包含上述类型之一   成员(包括,递归地,子集合或包含的联合的成员),或
  •   
  • 字符类型。
  •   

以上要求均未达到:

  • uint32_t与有效类型char不兼容。

  • 没有使用char的合格类型。

  • uint32_t不是char的无符号版本。

  • struct element没有uint32_t个成员。

  • uint32_t不是字符类型。

如果原始数组的有效类型为uint32_t,或者它将与malloc一起分配,在作业中发生有效类型,这将是合法的。

uint32_t arr;
foo((struct element*)&arr, 5); // Possible pointer conversion issues still apply

void * arr = malloc(4);
foo(arr, 5);

请注意,如果转换的地址无法存储在uint32_t* i = (uint32_t*)arr类型变量中,uint32_t*也可能会导致未定义的行为。但这是特定于实现的,因此取决于您的平台。

答案 1 :(得分:3)

这取决于您阅读arr的方式以及uint32_t value = *(uint32_t*)arr; 的分配方式。

如果您将其视为

arr

malloc要么动态分配(使用int32_t),要么分配为具有自动存储持续时间的int32_t对象(“在堆栈上”), 没关系。
如果是这种情况,您的写入会将有效类型更改为uint32_t 但是,如果您想使用与arr无关的类型而不是字符类型进行读取,则它是未定义的行为。

此外,int32_t需要与malloc正确对齐。 (如果是使用arr获得的,则会自动生成。)

在编辑问题之后,很明显它确实是未定义的行为,因为struct element arr[4] __aligned(4); 分配如下:

ng-model