我现在了解套接字,我发现它非常混乱,因为构建结构。
指南说要在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 :(得分: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)
个字节中(当struct
为{{1}时) } - 请参阅this了解为什么打包,但这是理想的情况。)
因此,想象一下,我们想创建另一个packed
以与此兼容。如果我们创建类似的东西:
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
字段first
的第三个字节,无论它具有哪个值。
但是,struct small_pair
呢?在struct开始之后它是a_pair->last
(15)个字节,但它明显超出了它的空间(0xf
只有14个。)
所以它将取决于变量在内存中加载的方式,但显然我们不会指代我们想要的值。最好的情况是当该地址超出我们的进程空间时,我们会得到一个Segmentation Fault,程序就会中止。但很可能是在记忆位置上声明了另一个变量,我们将从我们想要的内容中读取/写入一个不同的变量,留给谁知道结果。
因此,如果我们只是在sizeof(struct small_pair)
的末尾添加另一个2字节长的字段,我们保证struct small_pair
的每个可能引用在我们自己的{{1}中仍然是正确的因此,它们将在内存级别兼容。
然后,它仍然保留了语义级别的兼容性,但这是一个不同的故事:)
答案 1 :(得分:0)
如果我们谈论传统的C,那是不可能的,因为C转换指针而不是数据类型。如果使用指针执行此操作,程序将把char的字节作为int的最重要字节。随后的三个字节将填充char变量后面的任何内容。拜托,再也不要这样了!!!!!!!
答案 2 :(得分:0)
在Winsock中进行强制转换的原因是它们实现了一种奇怪的破坏形式的多态,其中所有结构都是相同的大小(因此在一些结构的末尾是未使用的字节数组),并且函数采用“通用”结构(例如sockaddr)。
因此,在适当的多态性的情况下,您将拥有:
class SockAddr
{
...
};
class SockAddrIn : public SockAddr
{
...
};
class SockAddrIn6 : public SockAddr
{
...
};
使用Winsock,你有几个不相关的结构都是二进制兼容的,你必须将它们传递给“泛型”sockaddr,当它们传递给函数时。