Невозможно понять приведение типов, выполненное в функции inet_ntoa.

Я понимаю функцию gethostbyname(). В то время я нашел следующий образец программы.

#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    char *host, **names, **addrs;
    struct hostent *hostinfo;

    if(argc == 1) 
    {
        char myname[256];
        gethostname(myname, 255);
    host = myname;
    }
    else
    host = argv[1];

    hostinfo = gethostbyname(host);
    if(!hostinfo) 
    {
        fprintf(stderr, "cannot get info for host: %s\n", host);
        exit(1);
    }

    printf("results for host %s:\n", host);
    printf("Name: %s\n", hostinfo -> h_name);
    printf("Aliases:");
    names = hostinfo -> h_aliases;
    while(*names) 
    {
        printf("%s", *names);
        names++;
    }
    printf("\n");

    if(hostinfo -> h_addrtype != AF_INET) 
    {
        fprintf(stderr, "not an IP host!\n");
        exit(1);
    }

    addrs = hostinfo -> h_addr_list;
    while(*addrs) 
    {
        printf(" %s", inet_ntoa(*(struct in_addr *)*addrs));
        addrs++;
    }
printf("\n");
exit(0);
}

теперь я запускаю его в своей системе. Он работает нормально. Есть две вещи, которые меня смущают:

  1. В функции inet_ntoa у нас есть регистр типа inet_ntoa(*(struct in_addr *)*addrs). Но если мы сделаем тип, например inet_ntoa((struct in_addr) addrs). Тогда он не работает. Я не могу понять причину этого. Пожалуйста, также объясните мне, какое приведение типов здесь делается.
  2. Когда я понимаю эту программу. Я также не могу понять следующий цикл while.

    while(*addrs) { printf(" %s", inet_ntoa(*(struct in_addr *)*addrs)); адрес++; }

    Пожалуйста, объясните мне об этом.

  3. Предположим, что есть элемент char**test, указывающий на строку "Индия". Когда мы когда-либо делали что-то вроде test++. Он увеличивается в соответствии с размером строки. В этом случае он будет увеличен на 6 (5 + 1 (нулевой символ)). Почему так?


person user3020306    schedule 22.11.2013    source источник
comment
Между *(struct in_addr *)*addrs и (struct in_addr) addrs есть существенные различия. Почему вы ожидаете, что они будут эквивалентны?   -  person DCoder    schedule 22.11.2013


Ответы (2)


I. В функции inet_ntoa используется тип inet_ntoa(*(struct in_addr *)*addrs). Но если мы делаем случай типа inet_ntoa ((struct in_addr) addrs). Тогда это не работает. Я не могу понять причину этого. Пожалуйста, также объясните мне, какое приведение типов здесь делается.

Для этого вы должны знать, что такое определение типа in_addr. Из MSDN

typedef struct in_addr {
  union {
    struct {
      u_char s_b1,s_b2,s_b3,s_b4;
    } S_un_b;
    struct {
      u_short s_w1,s_w2;
    } S_un_w;
    u_long S_addr;
  } S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

Members:
S_un
    S_un_b: An IPv4 address formatted as four u_chars.
    S_un_w: An IPv4 address formatted as two u_shorts.
    S_addr: An IPv4 address formatted as a u_long.

Здесь структура имеет объединение, из которого нас интересует chars. Так как addrs имеет тип char**, когда мы делаем *addrs, мы получаем char*, который является распавшимся типом массива char. В приведенном типе мы вручную конвертируем char* в struct in_addr*. Но inet_ntoa занимает объект in_addr по значению, а не по ссылке. Таким образом, мы добавляем еще один * к приведенному типу, чтобы изменить его с in_addr* на in_addr. Без случая выполнение **addrs дало бы char, а не in_addr.

II. while(*addrs) { printf(" %s", inet_ntoa(*(struct in_addr *)*addrs)); адрес++; }

To understand this loop you've see where you load addrs from: struct hostent::h_aliases which again MSDN documents as

A NULL-terminated array of alternate names.

addrs указывает на массив последовательностей символов (строк) с завершающим элементом NULL. Например, char *addrs[] = { "Delhi", "London", "New York", NULL }; Мы знаем, что addrs не равен нулю, но *addrs будет ненулевым только трижды, четвертый элемент будет равен NULL при проверке как while(*addrs).

III. Предположим, есть тест с одним символом, который указывает на строку «Индия». Когда мы когда-либо делали что-то вроде test++. Он увеличивается в соответствии с размером строки. В этом случае он будет увеличен на 6 (5 + 1 (нулевой символ)). Почему так?

Неправильный! char **test = "india"; является незаконным. Однако, как я объяснил выше, он будет указывать на массив таких строк. Когда вы делаете addrs++, на самом деле происходит не увеличение на основе длины строки, а просто увеличение на элемент. Когда вы сделаете *addrs, это будет указывать на "Дели", затем addrs++ и *addrs теперь будут указывать на "Лондон" и так далее.

Я бы порекомендовал вам прочитать Часто задаваемые вопросы по C, чтобы узнать подробности о затухании массива в указатель, арифметике указателей и т. д.

person legends2k    schedule 22.11.2013

1> Функция inet_ntoa() преобразует адрес хоста в Интернете, заданный в сетевом порядке байтов, в строку в десятичном формате с точками IPv4. Строка возвращается в статически выделенный буфер, который при последующих вызовах перезаписывается.

Прототип int_ntoa:

 char *inet_ntoa(struct in_addr in);

Эта строка, которую вы пишете «inet_ntoa((struct in_addr) addrs)», неверна. Как и в вашем коде, адрес является двойным указателем. вы вводите адрес приведения к «объекту in_addr», что неверно.

Строка *(struct in_addr *)*addrs или * ( (struct in_addr *)*addrs ) означает:

1.> преобразовать значение *addr (которое снова является адресом) в «struct in_addr *», то есть тип «in_addr *».

2.> А * ( (struct in_addr *)*addrs ) означает объект/значение типа in_addr.

2.> Второе:

 addrs = hostinfo -> h_addr_list;
    while(*addrs) 
    {
        printf(" %s", inet_ntoa(*(struct in_addr *)*addrs));
        addrs++;
    }

Здесь hostinfo -> h_addr_list возвращает указатель на массив, т. е. его адрес первого элемента.

addrs++ означает переход к следующему элементу в ряду. когда массив будет завершен, *addr будет нулевым.

inet_ntoa(*(struct in_addr *)*addrs , это преобразует весь байтовый адрес в строку.

person SeeTheC    schedule 22.11.2013