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