Неправильный вывод inet_ntop

Я пытаюсь напечатать IP-адрес из inet_ntop, но результат выглядит довольно странно.

Программа работает хорошо, мне удалось подключить сокет, но она печатает это:

H��H9�u�H�[]A\A]A^A_�ff.�

Вот мой код:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]){
    int sock = socket(AF_INET, SOCK_STREAM, 0); 
    struct addrinfo hints, *result;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
    hints.ai_flags = 0;

    int s = getaddrinfo("irc.root-me.org", "6667", &hints, &result);
    if( s != 0){ 
        printf("erreur\n");
        exit(EXIT_FAILURE);
    }   

    int f = connect(sock, result->ai_addr, result->ai_addrlen);
    if(f != 0){ 
        printf("erreur connect\n");
    }   

    struct sockaddr_in *sockin;  
    sockin = (struct sockaddr_in *)result->ai_addr;
    char  *dst;
    inet_ntop(AF_INET, &sockin->sin_addr, dst, sizeof(char *));
    printf("%s\n", dst);
    freeaddrinfo(result);

    exit(0);
}

person jehutyy    schedule 04.07.2015    source источник
comment
Спасибо всем за ваш ответ, я понял: никогда ничего не сохраняйте в указателе ^^   -  person jehutyy    schedule 04.07.2015


Ответы (2)


Здесь две проблемы:

  1. 3rd параметр для inet_ntop() должен быть массивом char или указателем на 1st элемент массива char.

  2. 4th параметр для inet_ntop() должен быть размером целевого буфера, адрес которого передается как 3rd параметр.

Что вы делаете, так это передаете неинициализированный char-указатель dst в качестве места назначения и сообщаете функции, что он будет указывать на sizeof(char*) байт памяти.

Адрес AF_INET (который имеет форму xxx.xxx.xxx.xxx) использует максимум 4x3 символа плюс 3 разделяющих . char, что в сумме дает 15 chars плюс 1 дополнительный char, используемый в качестве 0-терминатора, чтобы сделать его C-"строкой", поэтому исправленный код будет выглядеть так:

char dst[16] = ""; /* inet_ntop() does not necessarily 0-terminates the result. */
inet_ntop(AF_INET, &sockin->sin_addr, dst, sizeof dst);

Как указал Filipe Gonçalves в его комментарий можно использовать INET_ADDRSTRLEN (если доступно) вместо жестко закодированного "магического числа" " 16 для определения размера буфера для текстового представления адреса IPv4. Это хорошо.


Документация для inet_ntop() находится здесь:

person alk    schedule 04.07.2015
comment
Хороший ответ, но я бы предложил использовать INET_ADDRSTRLEN+1 (определено в arpa/inet.h) в качестве размера буфера (или INET6_ADDRSTRLEN+1 при работе с IPv6). - person Filipe Gonçalves; 04.07.2015
comment
Это снова я, я прочитал ваш ответ, и он мне очень помог, но я не понимаю, как вы поняли, что третий параметр должен быть массивом, а не указателем? Это const, который говорит вам об этом? - person jehutyy; 05.07.2015
comment
Я прочитал ваш комментарий, и он мне очень помог, но я не понимаю, как вы поняли, что третий параметр должен быть массивом, а не указателем? Это const, который говорит вам об этом? - person jehutyy; 05.07.2015
comment
Пожалуйста, ознакомьтесь с документацией. Я добавил туда ссылки. - person alk; 19.07.2018

Проблема

Проблема заключается в размере целевого char*, в котором вы пытаетесь сохранить результат, и в том факте, что он неинициализирован, то, что вы хотите сделать, это сохранить его в char[].

sizeof(char*) на x86 равен 4B и 8B на x64, IP-адреса обычно больше (адрес IPv4 составляет от 7 до 15 байтов) + 1 для нулевого терминатора.

Решение

Вы можете исправить код следующим образом:

char dst[16] = {0};
inet_ntop(AF_INET, &sockin->sin_addr, dst, sizeof(dst));

После исправления:

$ ./main
212.83.153.145

Исходный код

Если вам нужен полностью исправленный main.c, я загрузил на github.

person Matan M.    schedule 04.07.2015
comment
Хранение других типов в указателе, как правило, неправильно; это не просто размер указателя, а просто неправильный тип данных и не имеет ничего общего с размером указателя. - person too honest for this site; 04.07.2015
comment
Просто подсказка: вы не должны публиковать полную подсказку, так как это может показать больше, чем вы хотите показать. - person too honest for this site; 04.07.2015
comment
Я добавил упоминание о том, что это неправильный тип для использования, спасибо за исправление подсказки. - person Matan M.; 04.07.2015
comment
Добро пожаловать. Но это еще в правках - паутина не забывает. - person too honest for this site; 04.07.2015
comment
Что еще более важно, люди не получат плохой ответ. - person Matan M.; 04.07.2015