簡體   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