是否需要为所有成员对齐指针

时间:2015-03-10 16:20:22

标签: c alignment unions

鉴于

typedef union { unsigned char b; long l; } BYTE_OR_LONG;

拥有一个功能

是否合法
unsigned long get_byte_or_long(BYTE_OR_LONG *it)
{
  if (it->b)
    return it->b;
  else
    return decode_long(it->l); // Platform-dependent method
                               // Could return (it), (it>>8), etc.
}

并将其命名为

void test()
{
  long l = encode_long(12345678);  // Platform-dependent; could return
                                   // (it<<8), (it & 16777215), etc.
  char b[2] = {12,34};
  BYTE_OR_LONG *bl[3];
  bl[0] = (BYTE_OR_LONG*)&l;
  bl[1] = (BYTE_OR_LONG*)b;
  bl[2] = (BYTE_OR_LONG*)(b+1);
  for (int i=0; i<3; i++)
    printf("%lu\n", get_byte_or_long(bl[i]));
}

当然,构建未对齐的BYTE_OR_LONG *p然后访问p->l将是未定义的行为。此外,即使向(unsigned long*)转换未对齐指针的行为也将是未定义行为,因为对于char*这样的类型,实现可能不需要那么多位。然而,在工会中,事情似乎并不清楚。

据我所知,指向union的指针应该等同于指向其任何元素的指针。这是否意味着需要保证指向联合类型的指针必须能够识别其中包含的任何类型的任何实例[因此BYTE_OR_LONG*必须能够识别任何unsigned char],或者程序员是否只需要转换为联合类型指针,这些指针可以满足其中每个组成部分的每个对齐要求?

2 个答案:

答案 0 :(得分:0)

  

这是否意味着需要保证指向联合类型的指针必须能够识别其中包含的任何类型的任何实例的实现......?

长问题,简短回答:是的。

(我稍后会详细说明标准参考资料)

基本上它是因为struct / union的第一个元素保证在它之前不带填充。

答案 1 :(得分:0)

  

指向对象类型的指针可以转换为指向不同对象类型的指针。如果生成的指针未正确对齐引用类型[...],则行为未定义。 [C11(n1570)6.3.2.3 p7]

我无法找到关于联合对齐要求的任何明确保证,因此转换为联合指针似乎并不严格符合。在我的计算机上,_Alignof(char)为1,但_Alignof(BYTE_OR_LONG)为4。

  

这是否意味着需要保证指向联合类型的指针必须能够识别其中包含的任何类型的任何实例的实现[因此BYTE_OR_LONG*必须能够识别任何未签名的char,或者是程序员只需要转换为联合类型指针,这些指针可以满足其中每个组成部分的每个对齐要求吗?

不,指向T的指针可能指向包含T的任何联合,而不一定是反过来。据我所知,工会的协调要求甚至可能比其所有成员的更严格。