-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)には前のフィールドの右側のバイトに格納されることstructです(いつ-パックされた理由を理解するためにこれ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は「構造体の開始から2バイト後の1バイトを読み取る」(0xabbd0aa2 - 0xabbd0aa0 = 2)です。つまり、これは、のフィールドの3番目のバイトになりfirstますstruct small_pair

しかし、どうa_pair->lastですか?構造体の0xf開始から(15)バイトですが、明らかにスペースが不足しています(sizeof(struct small_pair)わずか14バイト)。

したがって、変数がメモリにロードされる方法によって異なりますが、必要な値を参照していないことは明らかです。最良のケースは、そのアドレスがプロセススペースの外にあるため、セグメンテーションフォールトが発生し、プログラムが異常終了する場合です。しかし、そのメモリの位置に別の変数が宣言されている可能性があります。必要なものとは異なる変数を読み書きし、誰が知っているか、どのような結果になるかを任せます。

したがって、の末尾にさらに2バイトの長さのフィールドを追加するだけで、aのすべての可能な参照が引き続き正しいことstruct small_pairを保証するため、メモリレベルで互換性があります。struct pairstruct

それでも、セマンティックレベルの互換性は残っていますが、それは別の話です:)

于 2012-11-24T23:13:05.350 に答える
0

従来のCについて話している場合、Cはデータ型ではなくポインターをキャストするため、これは不可能です。ポインタを使用してこれを行うと、プログラムはcharのバイトをintの最上位バイトとして配置します。次の3バイトは、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 に答える