指標型別之間的轉換產生錯誤對齊的結果

由於指標對齊不正確,以下可能有未定義的行為:

 char *memory_block = calloc(sizeof(uint32_t) + 1, 1);
 uint32_t *intptr = (uint32_t*)(memory_block + 1);  /* possible undefined behavior */
 uint32_t mvalue = *intptr;

指標轉換時會發生未定義的行為。根據 C11,如果兩個指標型別之間轉換產生錯誤對齊的結果(6.3.2.3),則行為未定義。例如,uint32_t 可能需要對齊 2 或 4。

另一方面,calloc 需要返回一個適合任何物件型別的指標; 因此,memory_block 正確對齊,在其初始部分包含一個 uint32_t。然後,在 uint32_t 需要對齊 2 或 4 的系統上,memory_block + 1 將是奇數地址,因此沒有正確對齊。

觀察到 C 標準請求已經定義了強制轉換操作。這是因為在地址被分段的平臺上,位元組地址 memory_block + 1 甚至可能不具有作為整數指標的適當表示。

char *轉換為指向其他型別的指標而不考慮對齊要求有時會錯誤地用於解碼打包結構,例如檔案頭或網路包。

你可以使用 memcpy 避免因未對齊的指標轉換而產生的未定義行為:

memcpy(&mvalue, memory_block + 1, sizeof mvalue);

這裡沒有指向 uint32_t*的指標轉換,並且逐個複製位元組。

我們示例的此複製操作僅導致 mvalue 的有效值,因為:

  • 我們使用了 calloc,因此位元組被正確初始化。在我們的例子中,所有位元組都有值 0,但任何其他正確的初始化都可以。
  • uint32_t 是一種精確的寬度型別,沒有填充位
  • 任意位模式都是任何無符號型別的有效表示。