いいえ、単なる慣例ではありません。
sockaddr
sockaddr_in
は、あらゆる種類のソケット操作の汎用記述子です。 IP ベースの通信 (IIRC、「in」は「InterNet」を表します) に固有の構造体です。私の知る限り、これは一種の「ポリモーフィズム」です:bind()
関数は struct sockaddr *
を取るふりをします 、しかし実際には、適切なタイプの構造体が渡されると想定します。私。 e.最初の引数として指定したソケットのタイプに対応するもの。
この質問に非常に関連するかどうかはわかりませんが、C
にあまり時間を費やしていない多くの人々として、型キャストをより理解しやすくする追加情報を提供したいと思います。 そのようなタイプカーストを見ると混乱します。
macOS
を使用しています であるため、システムのヘッダー ファイルに基づいた例を使用しています。
struct sockaddr
は次のように定義されます:
struct sockaddr {
__uint8_t sa_len; /* total length */
sa_family_t sa_family; /* [XSI] address family */
char sa_data[14]; /* [XSI] addr value (actually larger) */
};
struct sockaddr_in
は次のように定義されます:
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
非常に基本的なことから始めて、ポインターにはアドレスが含まれているだけです。だから struct sockaddr *
と struct sockaddr_in *
ほとんど同じです。どちらもアドレスを保存するだけです。関連する唯一の違いは、コンパイラがオブジェクトを処理する方法です。
(struct sockaddr *) &name
と言うと 、コンパイラをだまして、このアドレスが struct sockaddr
を指していると伝えているだけです タイプしてください。
ポインタが場所 1000
を指しているとしましょう . struct sockaddr *
の場合 このアドレスを保存すると、1000
からのメモリが考慮されます sizeof(struct sockaddr)
まで 構造定義に従ってメンバーを所有します。 struct sockaddr_in *
の場合 1000
からメモリと見なされる同じアドレスを保存します sizeof(struct sockaddr_in)
へ .
そのポインタを型キャストすると、sizeof(struct sockaddr)
までの同じバイト シーケンスが考慮されます。 .
struct sockaddr *a = &name; // consider &name = 1000
a->sa_len
にアクセスすると 、コンパイラは場所 1000
からアクセスします sizeof(__uint8_t)
へ sockaddr_in
の場合と同じバイトサイズです .したがって、これは同じバイト シーケンスにアクセスする必要があります。
sa_family
も同じパターン .
その後、struct sockaddr
に 14 バイトの文字配列があります in_port_t sin_port
からのデータを保存します (typedef
'd 16 ビット符号なし整数 =2 バイト)、struct in_addr sin_addr
(単に 32 ビットの ipv4 アドレス =4 バイト) および char sin_zero[8]
(8 バイト)。これら 3 つを合計すると 14 バイトになります。
現在、これら 3 つはこの 14 バイトの文字配列に格納されており、適切なインデックスにアクセスして再度型キャストすることで、これら 3 つのいずれかにアクセスできます。
user529758 の回答では、これを行う理由が既に説明されています。
これは、bind が IP ソケット以外のタイプのソケット (たとえば、タイプとして sockaddr_un を持つ Unix ドメイン ソケット) をバインドできるためです。 AF_INET ソケットのアドレスには、アドレスとしてホストとポートがありますが、AF_UNIX ソケットにはファイルシステム パスがあります。