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
, Однако это преобразование не совместимо. Следовательно, вы получаете ошибку компилятора во втором фрагменте, если вы пытаетесь выполнить прямое приведение.
В первом фрагменте вы по существу используете приведение указателей, чтобы обойти эту несовместимость типов.