为什么对 addr 变量进行类型转换?
Why is the addr variable type-converted?
在互联网上冲浪时,我发现了一个发送GET请求的c ++示例。我无法理解的这段代码的部分是为什么(请参阅粗体部分)变量 addr 进行类型转换。我知道该函数只接受某种类型。但是为什么要使用一个类型,然后将其转换为另一个类型呢?
#include <iostream>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
using namespace std;
int main()
{
int s, error;
struct sockaddr_in addr;
if((s = socket(AF_INET,SOCK_STREAM,0))<0)
{
cout<<"Error 01: creating socket failed!n";
close(s);
return 1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
inet_aton("204.27.61.92",&addr.sin_addr);
error = connect(s,(sockaddr*)&addr,sizeof(addr));
if(error!=0)
{
cout<<"Error 02: conecting to server failed!n";
close(s);
return 1;
}
char msg[] = "GET /beej/inet_ntoaman.html http/1.1nHOST: retran.comnn";
char answ[1024];
//cin.getline(&msg[0],256);
send(s,msg,sizeof(msg),0);
while(recv(s,answ,1024,0)!=0)
cout<<answ<<endl;
close(s);
cin.getline(&msg[0],1);
return 0;
}
这是运行时多态性,C 风格。
sockaddr
实际上是一个抽象基类 - 它不特定于任何具体类型的套接字。但是,每种套接字类型都需要特定于类型的信息。
由于 C 没有对多态性的语言支持,因此该技术是编写一个"派生"类型,该类型将"基"类型作为其第一个数据成员。这样,它们具有相同的地址,您可以在它们之间进行转换。
因此,(sockaddr*)&addr
是一个向上转换,生成指向有效基类子对象的指针。当您将其传递给AF_INET套接字时,它会将指针投射回(sockaddr_in*)
并恢复特定于 inet 的数据。
等效C++供参考,因为它更具表现力:
class SockAddr {
public:
virtual ~SockAddr();
enum Family { INET, UNIX, ... };
Family get_family() const { return family; }
protected:
explicit SockAddr(Family f) : family(f) {}
Family family;
};
class SockAddrInet: public SockAddr {
uint16_t port;
uint32_t addr;
public:
SockAddrInet(uint16_t port, uint32_t addr)
: SockAddr(SockAddr::INET), port(htons(port)), addr(addr)
{}
};
class SockAddrUnix: public SockAddr {
std::string path;
public:
explicit SockAddrInet(std::string path)
: SockAddr(SockAddr::UNIX), path(path) {}
};
void connect(Socket &s, SockAddr const &addr) {
switch (addr.get_family()) {
case SockAddr::INET:
connect_inet(s, dynamic_cast<SockAddrInet const&>(addr));
break;
case SockAddr::UNIX:
connect_unix(s, dynamic_cast<SockAddrUnix const&>(addr));
break;
}
}
这是一种在 C 语言中使用"子类型"的技术。还有其他各种sockaddr
类型(例如sockaddr_in6
适用于 IPv6)。被调用的函数检查sin_family
字段以确定传入的结构类型并相应地处理它。
struct sockaddr {
u_short sa_family;
char sa_data[14];
};
我们必须记住,套接字 API 可以使用许多不同的网络协议。每个协议都有完全不同的地址工作格式。因此,此sockaddr
结构是一个通用结构。它包含一个放置标识地址系列的位置,以及一个通用的"数据"字段,无论地址的格式如何,都可以放置地址。
但是,sockaddr_in
结构
struct sockaddr_in { /* socket address (internet) */
short sin_family; /* address family (AF_INET) */
u_short sin_port; /* port number */
struct in_addr sin_addr; /* IP address */
char sin_zero[8]; /* reserved - must be 0x00's */
};
这是专门为网络,IP地址设计的。此类型可以安全地类型转换为sockaddr*
,因为它与它对齐。
这是Richard Stevens在他的"UNIX网络编程"中所说的:
通用套接字地址结构
套接字地址结构在作为参数传递给 任何套接字功能。但是任何将这些指针之一作为 参数必须处理来自任何受支持协议的套接字地址结构 家族。 在如何声明传递的指针类型时出现问题。使用 ANSI C, 解决方案很简单:void *
是通用指针类型。但是,套接字函数早于 ANSI C,1982 年选择的解决方案是在<sys/socket.h>
标头中定义通用套接字地址结构(...
struct sockaddr {
uint8_t sa_len;
sa_family_t sa_family; /* address family: AF_xxx value */
char sa_data[14]; /* protocol-specific address */
};
然后,套接字函数被定义为获取指向通用套接字地址的指针 结构,如绑定函数的 ANSI C 函数原型所示:
int bind(int, struct sockaddr *, socklen_t);
这要求对这些函数的任何调用都必须将指向特定于协议的套接字地址结构的指针强制转换为指向通用套接字地址结构的指针。(...) 从内核的角度来看,使用指向通用套接字地址的指针的另一个原因 结构作为参数是内核必须获取调用者的指针,将其强制转换为struct sockaddr *
,然后查看sa_family
的值以确定结构的类型。 但从应用程序程序员的角度来看,如果指针类型是void *
的,省略了显式强制转换的需要,那就更简单了。
返回窗口的连接功能 ::connect
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx
它需要 sockaddr 作为参数类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++中的双指针类型转换
- 逐位操作的隐式类型转换
- 模板中的类型转换
- 在 C++(和 C)中进行类型转换时明显不一致
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- 为什么对 addr 变量进行类型转换?
- 类型转换时C++ (void *) 变量和 (void *&) 变量有什么区别
- 类型转换问题:字符数组的元素转换为整数变量
- 如何将DWORD或char*类型的变量转换为LPCWSTR
- 变量类型和变量模板的转换和输出运算符
- 将浮点数 32 位变量类型转换为无符号整数 32 位时进行了哪些位级更改
- 类型转换并将 void 指针变量分配给 VC++ 中的整数变量
- visualc++在转换变量时使用不同的基本类型
- 将c++的变量数据类型转换为c#
- c++ -强制类型转换变量以及如何处理它们
- 转换变量类型(或变通方法)
- C++将类型字符串变量中的单词转换为小写
- 为什么指向不同char类型的指针不能混合,而不同char类型的变量可以相互转换