2012-11-24 113 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它们传递给时功能。