[英]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.