私は、次のように定義されている関数に対するこの引数に混乱しています。
int bind(int s, const struct sockaddr *name, int namelen)
と呼ばれる
bind(sd, (struct sockaddr_in *) &addr, length);
ここで何struct sockaddr_in *
を意味するのか理解できません。
これは機能しますbind (sd, &addr, length);
か?
次のように呼び出す必要があります。
bind (sd, (struct sockaddr *) &addr, length);
理由については、これらの構造の定義を見ると、これがポリモーフィズムを行うCの方法です。
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
// IPv4 AF_INET sockets:
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
// IPv6 AF_INET6 sockets:
struct sockaddr_in6 {
u_int16_t sin6_family; // address family, AF_INET6
u_int16_t sin6_port; // port number, Network Byte Order
u_int32_t sin6_flowinfo; // IPv6 flow information
struct in6_addr sin6_addr; // IPv6 address
u_int32_t sin6_scope_id; // Scope ID
};
それらはすべて同じ最初のメンバーを共有しsa_family
ます。これらの構造の1つへのポインターをbind()
最初に関数にキャストするstruct sockaddr *
と、関数内で、sa_family
1つの関数ではなく、どの構造を渡して正しい構造にキャストバックするかを決定するために使用されます。構造ごとに、を受け入れる関数が1つありますsockaddr*
。
OOPの観点から見ると、それsockaddr
がとの基本クラスであるsockaddr_in
と想像してくださいsockaddr_in6
。ポインタをに渡すことsockaddr
は、基本型にキャストして総称関数を呼び出すことに似ています。これがそれをより明確にすることを願っています。
ポインタを除いて、ポインタからポインタへvoid
の変換は明示的である必要があります。T
U
bind (sd, (struct sockaddr *) &addr, length);
それは何であるかに依存しaddr
ます。
同じ構造体のアドレスでない場合は、型キャストする必要があります。そうでない場合は、から<type of addr>
への暗黙の型キャストの警告が表示されます。const struct sockaddr*
プログラムのコンパイル時にコンパイラによって表示されるすべての警告メッセージを表示します。これの使用を開始します(コンパイラのgcc
警告用):
gcc -Wall <test.c> -o <test>
これはプログラマーにとってのベストプラクティスです。