2012-04-23 93 views
1

我想創建一個函數,獲取一個空指針。這個指針指向一個任意的用戶數據。這與現在無關。描述這個用戶數據的描述符更重要。在這個數據下是。我想它的地址,有兩種不同的解決方案:奇怪的行爲與空指針

struct data_desc { 
    size_t size; 
    data_type_t type; 
    /* And so on... */ 
}; 

/* Operate on the descriptor */ 
void operate_on_data(void *ptr) 
{ 
    struct data_desc *desc; 
    /* Now I want to get the desc /* 

    /* This is the first approach, simply fails */ 
    desc = ((struct data_desc *)ptr) - sizeof(struct data_desc); 
    /* This is the second, it works...*/ 
    desc = (struct data_desc *)ptr; 
    desc--; 
    /* Do something with desc */ 
} 

正如你可以看到我用兩個不同勢的方法獲得描述符的地址。我認爲第一個更自然,但這不起作用。我用更多的括號來避免優先問題。

我知道這些方法不安全第一個不行,爲什麼?這種行爲背後的原因是什麼?

在此先感謝!

+0

能否請您明確一些事情? ptr指向什麼?類型或大小,還是什麼? – 2012-04-23 01:44:17

+0

這將是一個內存分配器,ptr傳遞給用戶,所以它可以是任何用戶數據。爲了組織這些塊,描述符存儲一些關於這個的信息,大小和前一個和第二個塊的指針。當free()來的時候,它只會得到ptr,所以它必須以某種方式獲得信息。最簡單的方法是將其附加到用戶數據。 – 2012-04-23 01:50:33

回答

2

問題是指針算術。當你拿一個指針並減去1時,你真的減去了(1*sizeof(struct))。帶「-sizeof」的第一個等式,你真的從指針中減去了(sizeof(struct) * sizeof(struct))個字節。合理?

1

當您將data_desc定義爲指向struct data_desc的指針時,編譯器知道在您將指針遞增或遞減1時加上或減去sizeof(struct data_desc)。換句話說,它將「一」轉化爲「一個結構」。

這是常見的像這樣寫代碼:

struct data_desc *desc = (struct data_desc *) ptr; 

然後,你可以操縱它是這樣的:

size_t sz0 = desc->size; // size of 0th element 
size_t sz1 = desc[1].size; // size of 1st element 
size_t sz2 = (desc + 2)->size; // size of 2nd element (slightly awkward) 
desc++; // Increment to next structure 

回到你原來的代碼:你可以desc = ((struct data_desc *)ptr) - 1;,但大多數程序員寧願初始化desc然後直接使用它。

+0

你說得對。第一種情況也是這樣做的。從ptr中減去就像將desc減1。我認爲問題在於字體大小。恕我直言,它應該與一個字符指針工作,因爲它只有一個字節寬,sizeof(struct desc_data)也是以字節爲單位。 – 2012-04-23 01:56:58

+1

我不完全確定你的意思。如果你說你可以定義'char * desc'然後使用你的原始計算,那麼你是對的......但是你不能解析desc,因爲它指向一個'char',而不是' data_desc'結構。 – 2012-04-23 01:58:36

1
desc = ((struct data_desc *)ptr) - sizeof(struct data_desc); 

你強制轉換ptrstruct data_desc *。現在,編譯器在這個指針上執行的所有算法都是指向它指向的類型的大小。

所以,如果你減去sizeof(struct data_desc)(假設struct data_desc的大小8個字節),ptr將指向可以容納8 struct data_desc本身ptr之間的位置。

假設每個loc下面可以容納一個struct data_desc

------------------------------------------------------------- 
|  |  |  |  |  |  |  |  |  |  | 
| loc | loc | loc | loc | loc | loc | loc | loc | loc | ptr | 
| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |  | 
------------------------------------------------------------- 
    ^           ^
     |            | 
    desc           ptr 
    location          location 
    after 
    subtraction