你能解釋一下接下來的兩行是做什么的嗎?
// Line 1
*(long *)add1= *(long *)add2。
//第二行
*(int *)add1 = *(int *)add2。
編輯1.我添加了我測驗的函式的完整代碼塊。 PS 這只是skript的一部分。[原始skript]
這是一個自定義的memcpy函式,將記憶體塊從A復制到B。
(2)
while(word_left > 0){
*(char *)temp = *(char *)src ;
word_left --。
}
return (void *)dest;
}
Vlag先生非常友好,并解釋了第(1)部分中的行的含義。
我的問題是關于第(2)部分的。如果記憶體地址發生重疊,這部分應該可以解決一個問題。
為什么我們要在這里使用char?為什么我們不能使用long或int呢?
uj5u.com熱心網友回復:
在這兩個記錄中的const6ructions ( long * )和( int * )意味著將指標相應地鑄造為指標型別long *和int *。然后這些指標被解除參考*( long * )addr2和*( int * )addr2以獲得對被指向物件的訪問,這些物件的值被分配給其他物件,這些物件也是通過鑄造和解除參考指標獲得的。
為了使其更加清晰,請考慮一個示范程式。
#include <stdio.h>
int main(void)
{
int x = 10;
int y = 0;
printf( "x = %d, y = %d
", x, y )。)
void *p1 = &x;
void *p2 = &y;
*( int * )p2 = *( int * )p1。
printf( "x = %d, y = %d
", x, y )。)
return 0;
程式輸出是
x = 10, y = 0。
x = 10, y = 10.
例如在這個程式中,指標p1的型別void *由于鑄造( int * )p1被解釋為int *型別的指標,指向int型別的物件(在這個例子中它指向物件x)。現在解參考這個指標*( int * )p1,你就可以直接訪問被指向的物件x。
你可能不只是寫,例如
y = *p1;
因為你不能解除對一個空指標的參考,因為void型別是一個不完整的型別。所以編譯器將不知道如何解釋指向的記憶體。
uj5u.com熱心網友回復:
C語言的標準函式memcpy有時也以類似的方式實作。這個函式沒有要求應用程式傳遞的地址是對齊的。
一個天真的版本可以只是使用char位元組型別運行一個for回圈,并逐個拷貝所有的東西。那么我們就不必擔心對齊問題,但是這樣的代碼將會很慢,因為它并沒有利用 CPU 的資料寬度。
更有效的代碼將在 CPU 能夠在一條指令中處理的最大資料大小上進行復制,例如 32 或 64 位。這應該就是這段代碼應該做的事情。如果我們這樣做的話,我們仍然要注意被復制段的起始和尾部位元組的潛在錯位。這一部分必須被逐個復制,類似于你函式末尾的代碼。
這是我們注意到你發布的代碼有嚴重缺陷的第一個地方 - 它沒有處理初始錯位。
更糟糕的是,它假定int cpu_size = sizeof(char *);給出了 CPU 資料寬度的大小,這顯然是錯誤的 - 指標的大小與地址總線寬度相對應,這與大量現有系統中的最大資料暫存器寬度不是一回事。
另一個問題/bug是,temp = cpu_size;并不是有效的C代碼,而是一個非標準的gcc擴展。我們不能對無效指標做指標算術。
算術錯誤是指void*和void*之間的轉換。很明顯,我們不需要在相同的型別之間進行轉換。事實上,C語言中的每個物件指標都可以被隱式地轉換為void*,而不需要轉換,只要限定符(const等)匹配即可。
最后,我們不能在標準的C語言編譯器上運行這樣的代碼,因為用long或int的值訪問方式去參考一些未知的資料很可能是未定義的行為和嚴格的別名違反。什么是嚴格別名規則?作為標準庫的一部分,實際的memcpy函式不是用標準C撰寫的,不能被編譯為標準C。(它很可能是用匯編程式撰寫的,并且經常在呼叫代碼中行內。)
那么你應該怎么做?
因此,你應該對這里的這段代碼做的是洗掉它,并忘記你曾經看到過它,因為從它那里沒有什么可學的。寫這段代碼的人并不知道他們在做什么。在 "Yoda條件 "的混淆下,它看起來像是20世紀80年代的代碼--如果是這樣,那么我建議避免研究這樣的老代碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/315461.html
標籤:
上一篇:strtok是如何作業的?
