Кастинг между sockaddr и sockaddr_in6
Я читал Beej Guide to Network Programming и в одном из своих примеров он наводил указатель на struct sockaddr
на указатель struct sockaddr_in6
, как показано ниже.
void *addr;
char *ipver;
// get the pointer to the address itself,
// different fields in IPv4 and IPv6:
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);
ipver = "IPv4";
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &(ipv6->sin6_addr);
ipver = "IPv6";
}
Как это возможно, так как размеры структур различны?
ai_family
и ai_addr
являются полями структуры addrinfo
, поэтому, предположительно, код, который вы цитируете, предварительно набрал getaddrinfo()
.
Результат getaddrinfo()
- это связанный с NULL связанный список структур addrinfo
, где поле addrinfo::ai_addr
является указателем на выделенный блок памяти, который имеет достаточный размер для хранения адреса сокета сообщенного addrinfo::ai_family
тип. Размер адреса указывается в поле addrinfo::ai_addrlen
.
Для AF_INET
поле addrinfo::ai_addr
указывает на блок памяти, содержащий структуру sockaddr_in
.
Для AF_INET6
поле addrinfo::ai_addr
указывает на блок памяти, содержащий структуру sockaddr_in6
.
Вот почему работают роли типа.
Поле addrinfo::ai_addr
объявляется как struct sockaddr*
, поэтому оно может передаваться как-есть в параметр addr
функций bind()
и connect()
без литья типов. Поле addrinfo::ai_addrlen
может быть передано как есть в их параметр addrlen
.