使用强制转换扩展结构的元素

时间:2017-03-14 11:14:59

标签: c pointers struct

我昨天在大学接受了这个问题/作业。它是这样的:

Give the following structure:

typedef struct _rect {
     int width;
     int height;
} rect;

How could you scale the width and height members using a cast to int* without explicitly accessing the two members?

所以基本上,鉴于结构,我该怎么做

rect *my_rectangle = malloc(sizeof(rect));
my_rectangle->width = 4;
my_rectangle->height = 6;

// Change this part
my_rectangle->width /= 2;
my_rectangle->height /= 2;

使用强制转换为int或int *?

4 个答案:

答案 0 :(得分:4)

您只能可靠地扩展第一个成员:

*((int *) my_rectangle) /= 2;

这不违反严格别名规则,因为标准明确允许将指向struct对象的指针转换为其第一个成员的指针。

  

C11§6.7.2.1/ 15结构和联合说明符

     

在结构对象中,非位字段成员和单位   哪些位字段驻留的地址按顺序增加   他们被宣布。适当地指向结构对象的指针   转换后,指向其初始成员(或者如果该成员是   位字段,然后到它所在的单元,反之亦然。   结构对象中可能有未命名的填充,但不在其中   开始。

假设这些成员之间没有填充,第二个成员也可以缩放,只要指针与成员具有相同(兼容)类型,即int。 / p>

答案 1 :(得分:1)

他们试图教你的是这个结构如何在记忆中表现出来。它有两个int成员,所以在内存中它也可能被视为一个int数组。所以以下内容可能会奏效。

rect *my_rectangle = malloc(sizeof(rect));
my_rectangle->width = 4;
my_rectangle->height = 6;

int *my_array=(int *) my_rectangle;
my_array[0] /= 2;
my_array[1] /= 2;

但这是一个非常糟糕的黑客攻击,编译器完全有可能以完全不同的方式存储你的结构,这样将它转换为int *就不会产生预期的效果。所以如果你想写好干净的可移植代码恕我直言,那就完全不推荐了。

如果有人要更改结构,例如通过制作宽度&高度为float而不是int,代码可能会在没有任何问题或警告的情况下进行编译,然后根本无法满足您的预期。

答案 2 :(得分:1)

您有结构的起始地址,因此您可以访问各个元素 通过相应地递增地址。这里因为两个类型都是int,所以你可以更好地使用整数指针来使用char指针。

 bannerAd?.isHidden = true

答案 3 :(得分:0)

这项任务值得怀疑,因为你很容易最终调用定义不明确的行为。

实际上,我们可以使用它,因为结构的类型是int,与指针类型相同,并且严格别名规则中有一个例外。

但仍存在填充问题,因此我们必须确保整数之间不存在填充。

模糊的结果是这样的:

// BAD. Don't write code like this!
#include <stddef.h>
#include <stdio.h>

typedef struct 
{
  int width;
  int height;
} rect;

int main (void) 
{
  rect my_rectangle;
  my_rectangle.width = 4;
  my_rectangle.height = 6;

  int* ptr = (int*)&my_rectangle;
  *ptr /= 2;

  _Static_assert(offsetof(rect, height) == sizeof(int), "Padding detected.");
  ptr++;
  *ptr /= 2;

  printf("%d %d", my_rectangle.width, my_rectangle.height);

  return 0;
}

使用union代替更好的做法。我们仍然会有相同的填充问题,但不必担心严格的别名。并且代码变得更容易阅读:

#include <stddef.h>
#include <stdio.h>

typedef union
{
  struct
  {
    int width;
    int height;
  };
  int array[2];
} rect;

int main (void) 
{
  rect my_rectangle;
  my_rectangle.width = 4;
  my_rectangle.height = 6;

  _Static_assert(offsetof(rect, height) == sizeof(int), "Padding detected.");

  my_rectangle.array[0] /= 2;
  my_rectangle.array[1] /= 2;

  printf("%d %d", my_rectangle.width, my_rectangle.height);

  return 0;
}