C++: Почему приведение в качестве указателя, а затем разыменование работает?

Недавно я работал над сокетами в 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 ответа

Решение

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

double q = 0.5;
int n;

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

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

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

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

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

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

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

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

Другие вопросы по тегам