[英]memcpy a void pointer to a union
碼:
union foo
{
char c;
int i;
};
void func(void * src)
{
union foo dest;
memcpy(&dest, src, sizeof(union foo)); //here
}
如果我這樣調用func()
:
int main()
{
char c;
int i;
func(&c);
func(&i);
return 0;
}
在呼叫func(&c)
,大小c
小於sizeof(union foo)
,這可能是危險的,是嗎?
memcpy
的行是否正確? 如果沒有,如何解決它?
我想要的是對memcpy
的安全調用,它將void *
指針復制到一個union
。
一點背景:這是從一個非常復雜的函數中提取的,包含void *
參數的func()
的簽名是我無法控制的。 當然,該示例沒有任何用處,因為我刪除了所有與提供最少代碼示例無關的代碼。
在呼叫
func(&c)
,大小c
小於sizeof(union foo)
,這可能是危險的,是嗎?
對,這將導致未定義的行為。 dest
可能包含來自c
周圍的內存區域的一些字節,這些字節取決於編譯器的內部工作方式。 當然,只要您只訪問dest.c
,在大多數情況下不應該導致任何問題。
但讓我更具體一點。 根據C標准,編寫dest.c
但讀取dest.i
將始終產生未定義的行為。 但是大多數平台上的大多數編譯器也會對這些情況有一些明確定義的行為。 所以經常寫dest.c
但是閱讀dest.i
是有道理的,盡管標准說的是什么。 然而,在這種情況下,從dest.i
讀取仍然會受到未知周圍變量的影響,因此它不僅從標准的角度來看是不確定的,而且在非常實際的意義上也是如此。
您還應該考慮一種罕見的情況: c
可能位於已分配內存頁的最末端。 (這是指從操作系統和最終內存管理單元(MMU)硬件分配的內存頁,而不是由malloc
和朋友完成的逐塊用戶空間分配。)在這種情況下,讀取多個單字節可能會導致訪問未映射的內存,因此導致嚴重錯誤,很可能是程序崩潰。 鑒於你的c
作為main中的自動變量的位置,這似乎不太可能,但我認為這個代碼片段只是一個例子。
memcpy
的行是否正確? 如果沒有,如何解決它?
取決於你想做什么。 就目前而言,代碼沒有多大意義,所以我不知道你可能會想到什么樣的正確合理的應用程序。 也許您應該將src
對象的sizeof
傳遞給func
。
memcpy的行是否正確? 如果沒有,如何解決它?
你應該傳遞void指針指向的內存大小 ,這樣你就可以知道src
有這么多的大小,所以你只需要復制這么多的數據......
為了更安全,你應該計算目的地的大小,並根據你應該通過大小,這樣可以避免讀寫時的非法訪問 。
memcpy
很好。 通過傳遞聯盟中最小成員的地址,您將在較大的成員中以垃圾結束。 避免垃圾位的一種方法是默認情況下對func
所有調用 - 我假設你控制它 - 只使用指向較大成員的指針 - 這可以通過將較大的成員設置為較小的成員來實現: i = c
然后調用func(&i)
。
func
本身還可以。
問題在於調用者是否確實在調用func()
時引用的內存至少是sizeof(union foo)
。
如果后者總是如此,一切都很好。 在OP的例子中,兩次調用func()
情況並非如此。
如果調用func()
時引用的內存小於sizeof(union foo)
則memcpy()
會引發未定義的行為。
既然你知道要復制什么和大小,為什么不給出一個更明確的函數,讓函數知道如何復制無效指針指向的正確大小的內存。
union foo
{
char c;
int i;
};
void func(void * src, const char * type)
{
union foo dest;
if(strcmp(type, "char") == 0){
memcpy(&dest, src, 1);
}else if(...){
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.