繁体   English   中英

使用演员表缩放结构的元素

[英]Scale elements of a structure using a cast

我昨天在大学的一次考试中遇到了这个问题/作业。 它是这样的:

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 *?

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

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

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

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

在结构对象中,非位字段成员和位字段所在的单元的地址按照声明的顺序增加。 指向经过适当转换的结构对象的指针指向其初始成员(或者,如果该成员是位字段,则指向它所驻留的单元),反之亦然。 结构对象内可能存在未命名的填充,但在其开始处没有。

假定这些成员之间没有填充,则第二个成员也可以缩放,只要指针的类型与该成员的类型相同(兼容),即int

他们试图教给你的是该结构如何在内存中表示。 它有两个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 *不会达到预期的效果。 因此,如果您要编写干净的便携式代码恕我直言,根本不建议这样做。

而且,如果有人要更改结构,例如通过使width&height为float而不是int ,则代码可能会编译而不会出现任何问题或警告,然后根本无法按预期运行。

您具有结构的起始地址,因此可以通过相应地增加地址来访问各个元素。 在这里,由于两种类型均为int类型,因此可以使用整数指针,否则最好使用char指针。

int *ptr = my_rectangle;
*(ptr) /= 2;
*(ptr+1) /=2;

这项任务相当可疑,因为您很容易以定义不明确的行为告终。

碰巧的是,由于结构的类型为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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM