在实践中严格混叠

时间:2016-08-06 04:10:30

标签: c compilation

C11代码如下所示是未定义的行为:

// test.c
#include <stdio.h>

struct point2d {
  int x, y;
};

struct point3d {
  int x, y, z;
};

typedef struct point2d point2d;
typedef struct point3d point3d;

int foo(point2d *p, point3d *q) {
  p->x = -1;
  p->y = -2;
  q->x = 1;
  q->y = 2;
  q->z = 3;
  return p->x;
}

int main(void) {
  point3d r;
  int n = foo((point2d *) &r, &r);

  printf("%d\n", n);
  return 0;
}

事实上,它是:

wrc@raspberrypi:~ $ gcc -O0 test.c -o test; ./test
1
wrc@raspberrypi:~ $ gcc -O3 test.c -o test; ./test
-1

C11标准说(6.5 / 7):

  

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

     
      
  • 与对象的有效类型兼容的类型

  •   
  • 与对象的有效类型兼容的类型的限定版本

  •   
  • 与对象的有效类型对应的有符号或无符号类型的类型,

  •   
  • 对应于对象有效类型的限定版本的有符号或无符号类型的类型,

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

  •   
  • 字符类型。

  •   

我的问题是关于this种技术,你试图通过将指向较大结构的指针转换为指向较小结构的指针来隐藏信息,该结构不包含较大结构的所有成员。 / p>

这里是相关结构定义的摘要:

struct _GRealArray
{
  guint8 *data;
  guint   len;
  guint   alloc;
  guint   elt_size;
  guint   zero_terminated : 1;
  guint   clear : 1;
  gint    ref_count;
  GDestroyNotify clear_func;
};

struct _GArray
{
  gchar *data;
  guint len;
};

typedef struct _GRealArray GRealArray;
typedef struct _GArray      GArray;

这种技术是否已经违反了标准?如果不是:有什么区别?如果是的话:为什么这不重要?是否有一些实用指南允许您在这种情况下事实上违反标准而没有不良后果(与上面test.c示例相反)?

1 个答案:

答案 0 :(得分:0)

Garray示例将遵循相同的规则,如果它会强调它们,但它似乎小心避免。

对于用户代码,两种类型之间永远不会出现别名冲突,因为如果我看到这一点,GRealArray类型不可见,那么所有这些别名问题都不会出现在用户代码中有这两种类型。

对于实现的内部代码,似乎没有可能出现别名的原因,原因很简单,即每个函数中始终只有一个数组可见。或者更直接地说,

  

别名规则仅在存在潜在别名时适用。

即使它会,如果该实现始终对它处理的两个不同指针使用相同的类型,编译器仍然必须假设两个这样的指针可以指向同一个对象。

顺便说一下,这只会回答你的直接问题,而不是你所指向的代码的行为是否被明确定义。这将要求对该代码进行深入审查。