了解 C 中的 getaddrinfo 函数

Understanding getaddrinfo function in C

我是 C 和套接字编程的新手,只是一个关于 getaddrinfo 函数的问题。 getaddrinfo的函数原型为:

int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);

getaddrinfo return是一个结果,指向一个addrinfo结构的链表,每个结构指向一个socket地址结构,对应host和service。

以下是我的问题:

Q1 - 为什么它需要 return 指向 链表 addrinfo 结构的结果?我的意思是给定一个主机和服务,这些只是一个唯一的套接字地址,它怎么可能不止一个有效的套接字地址,所以需要一个链表?

Q2-最后一个参数是struct addrinfo **result,为什么是指向指针的指针?为什么它不是 struct addrinfo *result,然后 getaddrinfo 在内部创建某物并让 result(struct addrinfo *) 指向它? 有人说这是由于 getaddrinfo 内部调用 malloc,但我也可以这样编码

int main() 
{
   char *ptr_main;
   test(ptr_main);
   free(ptr_main);
}

void test(char * ptr)
{ 
    ptr = malloc(10); 
}

所以函数的参数是char *ptr,而不是char **ptr

getaddrinfo() returns 一个地址列表,因为一个主机名可以有多个地址。以那些需要通过不同 IP 分配访问者的高流量站点为例。

自从 getaddrinfo()

combines the functionality provided by the gethostbyname(3) and getservbyname(3) functions into a single interface, but unlike the latter functions, getaddrinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 dependencies

它可能会触发 DNS 会话来解析主机名。对于上述那些高流量站点,相同的主机名将对应于实际地址列表。


你还问:

struct addrinfo **result, why is it a pointer to a pointer?

在 C 中,指向某物的指针在必须修改某物时作为函数的参数传递。因此,例如,如果您需要修改一个整数,您可以传递 int *。这种特殊的 修改 在 C 中很常见,当你想通过参数 return 某些东西时;在我们之前的示例中,我们可以通过访问作为参数传递的指针来 return 一个额外的整数。

但是如果一个函数想要分配一些东西怎么办?它将在内部产生 type * var = malloc(),这意味着指向 type 的指针将被 returned。为了 return 它作为参数,我们需要传递一个 type ** 参数。

逻辑清楚了吗?给定一个 type,如果你想 return 它作为参数,你必须将它定义为指向 type.

的指针

综上所述,在我们的例子中函数getaddrinfo需要修改一个类型为struct addrinfo *的变量,所以struct addrinfo **是参数类型。

顺便提一下这个参数的含义:

The getaddrinfo() function allocates and initializes a linked list of addrinfo structures, one for each network address that matches node and service, subject to any restrictions imposed by hints, and returns a pointer to the start of the list in res. The items in the linked list are linked by the ai_next field.

如你所见,我们实际上在函数内部有一个分配。所以这个内存最终需要被释放:

The freeaddrinfo() function frees the memory that was allocated for the dynamically allocated linked list res.


为什么不只是一个 type * 参数?

您的代码示例导致未定义的行为,当我 运行 它导致程序崩溃。

为什么?是我上面写的,在C中参数是按值传递的。这意味着在 func(int c) 函数的情况下,以这种方式调用

int b = 1234;

funct(b);

函数内部使用的参数 c 将是 bcopy,对其的任何更改都不会在函数外保留.

func(char * ptr) 的情况下也会发生同样的情况(请注意巨大的间距,以强调类型是 char * 并且变量是 ptr):[= 上的任何更改31=] 将无法在函数外存活。 **您将能够更改它指向的内存,并且这些更改将在函数 returns 之后可用,但作为参数传递的变量将与调用 [=33 之前相同=].

在您的示例中,在调用 test 之前,ptr_main 的值是多少?我们不知道,因为变量未初始化。因此,行为未定义。

如果你还有疑惑,这里有一个程序演示通过值获取的新分配的地址不能从外部访问the function:

#include <stdlib.h>
#include <stdio.h>

void test(char * ptr)
{ 
    ptr = malloc(10); 

    printf("test:\t%p\n", ptr);
}

int main() 
{
    char *ptr_main = (char *) 0x7777;

    printf("main-1:\t%p\n", ptr_main);
    test(ptr_main);
    printf("main-2:\t%p\n", ptr_main);
}

输出:

main-1: 0000000000007777
test:   0000000000A96D60
main-2: 0000000000007777

即使在函数调用之后 ptr_main 的值与我初始化后的值相同 (0x7777)。