C ++: Почему приведение в качестве указателя, а затем разыменование работает? - PullRequest
4 голосов
/ 24 сентября 2011

Недавно я работал над сокетами в C ++, и я столкнулся с этим:

*(struct in_addr*)&serv_addr.sin_addr.s_addr = *(struct in_addr *)server->h_addr;

Хотя это делает то, что я хочу, я немного растерялся, почему я не могу этого сделать:

(struct in_addr)serv_addr.sin_addr.s_addr = *(struct in_addr *)server->h_addr;

Поскольку он становится указателем, а затем немедленно разыменовывается, разве вторая не должна работать так же хорошо, как первая? Я все еще новичок в C ++, и это немного смущает меня. Любая помощь будет принята с благодарностью. Ниже приведен код. Все, что он делает, это берет имя хоста или IP и выводит IP на экран.

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


using namespace std;

int main(){

    int socketfd, portno, rwResult; 
    struct sockaddr_in serv_addr; 
    struct hostent* server;     
    char inputName[50];

    //The next block gets the host name and port number and stores them in variables
    cout<<"Enter host(Max Size 50): ";
    cin>>inputName;
    cout<<endl<<"Enter port number: ";
    cin>>portno;
    cout<<endl;

    server = gethostbyname(inputName);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);

    *(struct in_addr*)&serv_addr.sin_addr.s_addr = *(struct in_addr *)server->h_addr;
    //This is where I am confused
    //(struct in_addr)serv_addr.sin_addr.s_addr = *(struct in_addr *)server->h_addr;


    cout<< "Server: "<<inet_ntoa(*(struct in_addr *)server->h_addr_list[0])<<endl;

    cout<< "Server: "<<inet_ntoa(*(struct in_addr *)&serv_addr.sin_addr.s_addr)<<endl;
    //The two cout's tell me if the address was copied correctly to serv_addr I believe.



    return 0;
}

Ответы [ 3 ]

4 голосов
/ 24 сентября 2011

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

С другой стороны, указатели могут быть преобразованы произвольно.Однако это может быть очень опасно.Если необходимо выполнить приведение, используйте static_cast или dynamic_cast при этом и, возможно, проверьте, успешно ли приведено приведение.Еще одно дополнительное стилистическое преимущество при использовании этого более явного способа заключается в том, что оно делает его более откровенным для тех, кто просматривает ваш код.

3 голосов
/ 24 сентября 2011

Более простой пример может помочь объяснить разницу:

double q = 0.5;
int n;

n = (int) q;    // #1
n = *(int*)(&q) // #2

Первая версия преобразует значение из q в значение типа int в соответствии с правилами языка. Преобразование возможно только для примитивных типов и для классов, которые определяют операторы / конструкторы преобразования.

Вторая версия интерпретирует двоичное представление q как целое число. В хороших случаях (как в вашем примере) это приводит к чему-то полезному, но в целом это неопределенное поведение, так как не разрешается обращаться к переменной одного типа через указатель на другой тип.

Ваш пример может быть верным, поскольку оба рассматриваемых типа являются структурами POD с одинаковыми начальными элементами, и вы получаете доступ только к одному из общих начальных элементов. Редактировать. Я проверил, server->h_addr имеет тип char *. Возможно, это просто заполнитель, а указатель фактически является структурой правильного типа.

3 голосов
/ 24 сентября 2011

То, что делает код, пытается интерпретировать serv_addr.sin_addr.s_addr как тип in_addr. Однако это преобразование не совместимо. Следовательно, вы получаете ошибку компилятора во втором фрагменте, если вы пытаетесь выполнить прямое приведение.

В первом фрагменте вы по существу используете приведение указателя, чтобы обойти эту несовместимость типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...