C標準很清楚。由p
命名的對象的有效類型爲void*
,因爲它具有聲明的類型,請參閱6.5/6
。 C99中的別名規則適用於讀取和寫入,並且根據6.5/7
寫入void*
到unsigned
左值(1)
是未定義的行爲。
相比之下,(2)
的memcpy
是精細的,因爲unsigned char*
可以別名任何對象(6.5/7
)。標準在7.21.2/1
定義memcpy
作爲
對於本節的所有功能,每一個字符應被解釋爲,如果它有類型無符號的字符(並因此每個可能的對象表示是有效的,並具有一個不同的值)。
memcpy函數將s2指向的對象中的n個字符複製到s1指向的對象中。如果在重疊對象之間進行復制,則行爲不確定。
但是,如果之後存在對p
的使用,則可能會導致取決於bitpattern的未定義行爲。如果這樣的使用不會發生,該代碼是C.
精細按照C++標準,這在我看來是很不明朗的問題,我覺得有以下成立。請不要將這種解釋視爲唯一可能 - 模糊/不完整的規範留下了很多投機空間。
行(1)
有問題,因爲&p
的對齊方式可能不適用於unsigned
類型。它將存儲在p
中的對象的類型更改爲unsigned int
。只要您稍後通過p
不訪問該對象,則別名規則不會被破壞,但對齊要求可能仍然存在。然而(2)
線沒有對齊的問題,因此是有效的,只要你不訪問p
事後作爲void*
,取決於void*
類型如何解釋存儲位模式這可能會導致不確定的行爲。我不認爲對象的類型會因此而改變。
還有一個很長的GCC Bugreport,它還討論了通過這樣一個轉換導致的指針寫入的影響,以及與新位置的不同之處是什麼(該列表中的人不同意它是什麼)。
請在Marcelo的回答的評論中看到問題。對此有何評論? – zvrba 2010-07-18 17:48:22
@zvrba,哦,沒有什麼不同。您只需在中間加入'void *',這等於直接投射。如果你想「模擬」memcpy,你必須像'unsigned char * pc =(unsigned char *)&p,* i =(unsigned char *)&x; * pc = * x; * pC++ = * x ++; ......,這就是它所做的。 – 2010-07-18 19:17:38
如果srcptr和destptr相等,memcpy()涉及的對象是否被認爲是「重疊的」,或者是否有任何明確允許該場景的語言? – supercat 2011-11-20 21:44:16