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