2012-11-24 144 views
-1

我現在瞭解了套接字,我發現它非常混亂,因爲鑄造結構。用c語言編寫的代碼

該指南聲稱包含sockaddr_in中的8位以將其與sockaddr進行比較。

所以我的問題是,爲什麼做我的意思是,當你投你不比較的字符尺寸爲int

例如你做

char a[1]='1'; 
int b=(int)a; 

,而不是

char a[2]='1';//compare to size of int 
int b=(int)a; 

所以它是如何工作的?

它的castig結構是否不同? 如果是,那麼爲什麼?

+0

'char a [2] ='1''不會編譯也不會'char a [1] ='1'' –

+0

爲什麼它不會編譯? – user1801625

+0

你不能施放'struct's,所以我不知道這是關於什麼的。 – melpomene

回答

1

傳遞指向結構的指針時,接收它的函數可能會嘗試訪問其所有字段中的任何一個。

如果您收到struct something *,您希望您可以讀取接收到的指針後面的任何sizeof(struct something)字節。所以,不保留這些字節在你自己的struct會使它們不兼容 - 只要函數試圖訪問你沒有分配的字節,它就會訪問非保留的內存,所以它可能是一個分段錯誤,或者可能會破壞另一個的結構數據。


看看這個程序:

#include <stdlib.h> 
#include <stdio.h> 

struct __attribute__ ((__packed__)) pair { 
     short first; 
     char second; 
     long int third; 
     int forth; 
     char last; 
}; 

void main(void) { 
     struct pair myPair; 
     printf("myPair   is at 0x%x\n", &myPair); 
     printf("myPair.first is at 0x%x\n", &(myPair.first)); 
     printf("myPair.second is at 0x%x\n", &(myPair.second)); 
     printf("myPair.third is at 0x%x\n", &(myPair.third)); 
     printf("myPair.forth is at 0x%x\n", &(myPair.forth)); 
     printf("myPair.last is at 0x%x\n", &(myPair.last)); 
} 

和一個樣本輸出:

myPair   is at 0xabbd0aa0 
myPair.first is at 0xabbd0aa0 
myPair.second is at 0xabbd0aa2 
myPair.third is at 0xabbd0aa3 
myPair.forth is at 0xabbd0aab 
myPair.last is at 0xabbd0aaf 

我們在這裏學到的是,每個字段下一個存儲的前一個內存,更準確地說是sizeof(previous_field)個字節到前一個字段的右側(當structpacked - 請參閱this瞭解爲什麼包裝,但是th是理想的情況)。

所以,想象一下,我們想創建另一個struct與此兼容。如果我們創建類似:

struct __attribute__ ((__packed__)) small_pair { 
     long int first; 
     char second; 
     int third; 
     char forth; 
}; 

我們可以通過一個struct small_pair *給需要一個struct pair *由鑄造任何功能:

void my_function(struct pair *); 

void main(void) { 
    struct small_pair my_small_pair; 
    // ... 
    my_function((struct pair*) &my_small_pair); 
    // ... 
} 

void my_function(struct pair *a_pair) { 
    //... 
    printf("Second character of pair is %c\n", a_pair->second); 
    //... 
    printf("Last character of pair is %c\n", a_pair->last); 
    //... 
} 

一旦編譯,訪問a_pair->second是「讀一個字節是兩個字節「結構開始之後」(0xabbd0aa2 - 0xabbd0aa0 = 2)。所以這將是struct small_pair的字段first的第三個字節,無論它有哪個值。

但是,a_pair->last呢?在結構開始之後它是0xf(15)個字節,但它明顯超出了它的空間(sizeof(struct small_pair)僅爲14)。

所以它將取決於變量加載到內存中的方式,但顯然我們不會指向我們想要的值。最好的情況是,當這個地址超出我們的進程空間時,所以我們得到一個分段錯誤,程序中止。但很可能存在另一個在內存中聲明的變量,我們將從我們想要的內容讀取/寫入一個不同的變量,留下誰知道什麼結果。

所以,如果我們只是再添2字節長的字段添加到struct small_pair年底,我們保證一個struct pair的每一個可能的基準仍是正確的在我們自己struct,所以他們會在內存兼容-水平。

然後,它仍然留在語義級別的兼容性,但是這是一個不同的故事:)

+0

那麼它不是真的鑄造它的指針? – user1801625

+0

@ user1801625我剛剛編輯了我的答案,希望它有助於澄清這一點。 – mgarciaisaia

+0

哇謝謝你,非常幫我:) – user1801625

0

如果我們正在談論傳統的C這是不可能的,因爲C轉換指針而不是數據類型。如果你用一個指針來做這件事,你的程序會把char的字節作爲int的最高有效字節。隨後的三個字節將填充您的char變量後面的任何內容。請不要再這樣做!!!!!!!

0

原因在Winsock的石膏是他們實現多態性的一種奇怪的破碎形式,其中所有的結構都是一樣的大小(因此在某些結構的末尾有未使用的字節數組)和函數採用「通用」結構(例如sockaddr)。

所以當與適當的多態性你會:

class SockAddr 
{ 
    ... 
}; 

class SockAddrIn : public SockAddr 
{ 
    ... 
}; 

class SockAddrIn6 : public SockAddr 
{ 
    ... 
}; 

的Winsock你有都是二進制兼容的幾個不相關的結構,你必須將它們轉換成「通用」的sockaddr它們傳遞給時功能。