为什么某些 C 程序使用箭头运算符来指向结构的一部分而不是直接引用?

Why do certain C programs use an arrow operator to point to parts of a structure instead of directly referencing?

我正在开发一个 winsock2 程序,MSDN 上的一行代码引起了我的注意:

ConnectSocket=socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);

为什么使用指针来引用结构而不是直接用点运算符引用结构?

编辑:查看此处的代码:Creating a Socket for the Client

在C/C++中,->运算符用于访问指针指向的对象的属性和函数(即myClass->propOne)。请记住,指针只是对内存的引用,您可以看到它不会有 propOne,因为它只是一个内存位置。 -> 运算符表示您要访问位于 myClass 指向的内存中的对象的 propOne

您也可以通过使用 * 运算符取消引用指针来访问对象,然后使用 . 运算符访问道具(即 (*myClass).propOne)来实现这一点.

它们都有效,但 -> 更简洁一些,并且可以减少编码错误。

解决 为什么 问题,使用指针的原因有很多。有时您想传递一个值或一个结构,但又不想复制它。有时您可能希望不止一件事能够轻松访问相同的结构。有时它只是更容易和更清洁。

. 运算符用于在对

进行操作时访问对象的成员
  1. 对象直接:

    Type obj;
    obj.member
    
  2. 对对象的引用:

    Type obj;
    Type &ref = obj;
    ref.member
    

当您在 指向对象的指针上操作时,-> 运算符用于访问对象的成员 而不是:

Type obj;
Type *ptr = &obj;
ptr->member

-> 运算符只是将 *. 运算符一起使用的更简洁的方式:

Type obj;
Type *ptr = &obj;
(*ptr).member

在这种情况下,由于 ptr 是一个指针,您可以使用 ->*. 访问其成员。

在链接示例中,ptr 是指针的原因是代码使用了 getaddrinfo(), which returns a dynamically allocated linked-list of addrinfo 结构,其中 ptr 是指向列表中特定项目的指针。

MSDN 示例仅访问列表中的第一项,但习惯上循环遍历整个列表,因为 getaddrinfo() 可以 return 多个地址。您需要使用指针循环遍历列表,例如:

#define DEFAULT_PORT "27015"

int main(int argc, char** argv)
{
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo *result = NULL,
                    *ptr = NULL,
                    hints;
    int iResult;
    WSADATA wsa;

    iResult = WSAStartup(MAKEWORD(2, 0), &wsa);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC; // allows IPv4 and IPv6 addresses
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo(argv[1], DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Attempt to connect to each address returned by
    // the call to getaddrinfo until one succeeds
    for(ptr = result; ptr != NULL; ptr = ptr->ai_next)
    {
        // Create a SOCKET for connecting to server
        ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (ConnectSocket == INVALID_SOCKET) {
            printf("Error at socket(): %ld\n", WSAGetLastError());
            continue;
        }

        // connect to server
        iResult = connect(ConnectSocket, ptr->ai_addr, ptr->ai_addrlen);
        if (iResult == 0) {
            printf("Connected!\n");
            break;
        }

        printf("Unable to connect: %ld\n", WSAGetLastError());

        // Destroy the SOCKET before trying the next address
        closesocket(ConnectSocket);
        ConnectSocket = INVALID_SOCKET;
    }

    freeaddrinfo(result);

    if (ConnectSocket != INVALID_SOCKET) {
        // use ConnectSocket as needed...
        closesocket(ConnectSocket);
    }

    WSACleaup();
    return 0;
}
ISO/IEC 9899:TC3

6.5.2.3 Structure and union members

The first operand of the . operator shall have a qualified or unqualified structure or union type, and the second operand shall name a member of that type.

The first operand of the -> operator shall have type ‘‘pointer to qualified or unqualified structure’’ or ‘‘pointer to qualified or unqualified union’’, and the second operand shall name a member of the type pointed to.