-1

我现在了解套接字,我发现它非常混乱,因为转换结构。

该指南说在 sockaddr_in 中包含 8 位以将其与 sockaddr 进行比较。

所以我的问题是为什么要这样做我的意思是当你投射时你不会将 char 大小与 int 进行比较

例如你做

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

并不是

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

那么它是如何工作的呢?

它的铸件结构不同吗?如果是,那为什么?

4

3 回答 3

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)前一个字段右侧的字节(什么时候- 请参阅this以了解为什么要打包,但这是理想情况)。structpacked

所以,想象一下我们想要创建另一个struct与这个兼容。如果我们创建类似的东西:

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

我们可以通过强制转换将 a 传递struct small_pair *给任何期望 a 的函数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)。所以这将是 a 字段的第三个字节firststruct small_pair无论它具有哪个值。

但是,怎么a_pair->last办?它是0xf结构开始后的 (15) 个字节,但显然超出了它的空间(sizeof(struct small_pair)只有 14 个)。

所以这将取决于变量在内存中的加载方式,但显然我们不会引用我们想要的值。最好的情况是该地址超出我们的进程空间,因此我们得到一个分段错误,程序中止。但很可能在该内存位置声明了另一个变量,我们将读取/写入与我们想要的不同的变量,留给谁知道结果。

因此,如果我们只是在 的末尾添加另一个 2 字节长的字段struct small_pair,我们保证每个可能的 a 引用struct pair在我们自己的 中仍然是正确的struct,因此它们将在内存级别兼容。

然后,它仍然保留了语义级别的兼容性,但这是另一回事 :)

于 2012-11-24T23:13:05.350 回答
0

如果我们谈论的是传统的 C,这是不可能的,因为 C 转换的是指针而不是数据类型。如果您使用指针执行此操作,您的程序会将 char 的字节作为 int 的最高有效字节。后面的三个字节将填充 char 变量后面的任何内容。请不要再这样做了!!!!!!!

于 2012-11-24T23:11:30.637 回答
0

Winsock 中强制转换的原因是它们实现了一种奇怪的多态性破坏形式,其中所有结构的大小相同(因此在某些结构的末尾未使用的字节数组)并且函数采用“通用”结构(例如 sockaddr )。

因此,在使用适当的多态性时,您将拥有:

class SockAddr
{
    ...
};

class SockAddrIn : public SockAddr
{
    ...
};

class SockAddrIn6 : public SockAddr
{
    ...
};

使用 Winsock,您有几个不相关的结构,它们都是二进制兼容的,并且在将它们传递给函数时,您必须将它们转换为“通用”sockaddr。

于 2012-11-24T23:22:13.637 回答