簡體   English   中英

關於 c 中的指針轉換的混淆

[英]Confusion about pointer casts in c

char* p = (char*) malloc(8 * sizeof(char));
strcpy(p, "fungus");

for (int i = 0; i < strlen(p); i++) {
    printf("%c", p[i]);
}

char* p2 = (char*) malloc(4 * sizeof(char));
*p2 = *(uint16_t*) p;
printf("\nPointer: %c\n", p2[1]);

所以我創建了一個 char* p 來存儲字符串“fungus”。 據我了解,如果我將 p 類型轉換為 uint16_t* 並取消引用它,則返回的值應該是 p 指向的前 2 個字節。 因此,p2[1] 應該是“u”,因為“u”是字符串“fungus”中的第二個字節。 但是,當我運行我的程序時,情況並非如此。 我也嘗試打印 p[0] + 1,但這只是輸出“g”。 我的邏輯有錯誤嗎?

據我了解,如果我將 p 類型轉換為 uint16_t* 並取消引用它,則返回的值應該是 p 指向的前 2 個字節。

這是不正確的,至少有兩個原因。

One, a pointer to a char might not have the alignment required for a uint16_t , and then the conversion to uint16_t is not defined by the C standard, per C 2018 6.3.2.3 7:

... 如果結果指針未正確對齊 70) 用於引用類型,則行為未定義...

這不適用於問題中的示例代碼,因為char *是從malloc分配的,並且malloc始終返回適合任何基本類型對齊的地址。 但是,它可能適用於以其他方式創建的char * (包括向p添加偏移量,例如嘗試將p+1轉換為uint16_t * )。

Two, accessing objects defined as char (including those created by writing char values to memory allocated with malloc ) as if they were uint16_t violates the aliasing rules in C 2018 6.5 7. It is possible a C implementation might reinterpret the two char as a uint16_t ,但編譯器的優化也有可能將未定義的行為轉換為其他行為。

*p2 = *(uint16_t*) p;

此代碼是對單個 char *p2的賦值,即p2[0] ,而不管右側可能是 16 位值。 它不觸及p2[1]

如果*(uint16_t*) p; 確實將字符串的兩個 8 位字節重新解釋為uint16_t ,然后它將產生一些 16 位值,然后分配給單個char *p2 如果char是無符號的,則該值的低八位將存儲為p2[0] ,而p2[1]保持不變。 如果已簽名,則將執行實現定義的轉換,並將結果(如果未發生陷阱)分配給p2[0] ,同樣保持p2[1]不變。

然后printf("\nPointer: %c\n", p2[1]); 嘗試打印尚未初始化的值,因為p2[1]中沒有任何值。

您可以嘗試更改*p2 = *(uint16_t*) p; * (uint16_t *) p2 = * (uint16_t *) p; 復制uint16_t整體,而不是嘗試將其塞入單個字節。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM