C++ Bigendian/Littleendian混淆
我正在编写用于ipv4的遗留代码。现在,我为ipv6添加了类似的代码。我已经在主机上进行了尝试和测试。但是我担心它是否能在powerpc上工作,因为endianness…代码是从传入流中提取ip头并压缩它。任何注释都会有帮助C++ Bigendian/Littleendian混淆,c++,C++,我正在编写用于ipv4的遗留代码。现在,我为ipv6添加了类似的代码。我已经在主机上进行了尝试和测试。但是我担心它是否能在powerpc上工作,因为endianness…代码是从传入流中提取ip头并压缩它。任何注释都会有帮助 class st_ipv6 { //================================================================================================== public: //======
class st_ipv6
{
//==================================================================================================
public:
//==================================================================================================
#ifdef _BIG_ENDIAN
uint32 version:4; // version
uint32 trafficclass:8; // header length
uint32 flowlabel:20; // flow label
#else
uint32 trafficclass_1:4;
uint32 version:4; // version
uint32 flowlabel_1:4;
uint32 trafficclass_2:4; // traffic class
uint32 flowlabel_2:4; // flow label
uint32 flowlabel_3:4; // flow label
uint32 flowlabel_4:4; // flow label
uint32 flowlabel_5:4; // flow label
#endif
uint16 payloadlength; // payload length
uint8 nextheader; // next header
uint8 hoplimit; // hop limit
uint32 sourceaddress[4]; // source address
uint32 destinationaddress[4]; // destination address
#ifdef _BIG_ENDIAN
//**********************************************************************************************
//* Description:
/** Specify/Return IPv6 Version
*/
//**********************************************************************************************
inline void setVersion(uint8 ubyVersion)
{
version = ubyVersion;
}
inline uint8 getVersion()
{
return version;
}
我建议使用
struct
而不是class
,因为像RTTI这样的东西可以在内存布局中插入额外的东西
我认为这应该足够了
#ifdef _BIG_ENDIAN
uint32 version:4; // version
uint32 trafficclass:8; // header length
uint32 flowlabel:20; // flow label
#else
uint32 flowlabel:20; // flow label
uint32 trafficclass:8; // header length
uint32 version:4; // version
#endif
…但在读取flowlabel时应
ntohl(flowlabel)
,在设置它时应htonl(flowlabel)
。注意不同的编译器和使用位字段。一些编译器从高位开始位字段向下工作,而另一些编译器从低位开始工作。除非您在使用的不同编译器中仔细测试,否则最好自己对原始字节进行屏蔽。位字段和可移植性通常是一场噩梦。通常最好使用和/或/或转换
参见下面的示例
只要在读/写各种整数时调用hton*()/ntoh*(),就(希望)不会有问题
我还将编写其余的访问器,并将数据字段设置为私有
class st_ipv6
{
public:
uint32 version_info;
uint16 payloadlength;
uint8 nextheader;
uint8 hoplimit;
uint32 sourceaddress[4];
uint32 destinationaddress[4];
uint8 GetVersion()
{
return version_info & 0xF;
}
void SetVersion(uint8 v)
{
version_info = (version_info & ~0xF) | (v & 0xF);
}
uint8 GetTrafficClass()
{
return (version_info & 0xFF0)>>4;
}
void SetTrafficClass(uint8 c)
{
version_info = (version_info & ~0xFF0) | ((c & 0xFF) << 4);
}
uint32 GetFlowLabel()
{
return (version_info & 0xFFFFF000)>>12;
}
void SetFlowLabel(uint32 f)
{
version_info = (version_info & ~0xFFFFF000) | ((f & 0xFFFFF) << 12);
}
};
class st_ipv6
{
公众:
uint32版本信息;
uint16有效载荷长度;
下一个uint8;
uint8跳数极限;
uint32源地址[4];
uint32目的地址[4];
uint8 GetVersion()
{
返回版本信息&0xF;
}
无效设置版本(uint8 v)
{
版本信息=(版本信息&~0xF)|(v&0xF);
}
uint8 GetTrafficClass()
{
返回(版本信息&0xFF0)>>4;
}
void SetTrafficClass(uint8 c)
{
版本信息=(版本信息&~0xFF0)|((c&0xFF)>12;
}
无效设置流标签(uint32 f)
{
version_info=(version_info&~0xFFFFF000)|((f&0xFFFFF)非常感谢Michael。基于输入,我编写了一个简单的函数版本,并尝试进行基本测试,版本字段看起来还可以。我的程序看起来是这样的。现在唯一关心的是,当我们有了uint32数组时,比如src和dst地址
类别ip_v6{
公众:
uint32版本信息;
uint16有效载荷;
uint8下一个_头;
uint8跳数限制;
uint32 src_地址[4];
uint32 dst_地址[4]
uint32 GetVersionInfo()
{
返回(ntohl(版本信息));
}
无效设置版本信息(uint32 vinfo)
{
版本信息=htonl(vinfo);
}
uint8 GetVersion()
{
返回(((GetVersionInfo())和(0xf0000000))>>28);
}
无效设置版本(uint8 v)
{
SetVersionInfo((GetVersionInfo()&0x0fffffff)|(v20);
}
void SetTrafficClass(uint8 c)
{
SetVersionInfo((GetVersionInfo()&0xf00fffff)|(cI从未见过这样的事情,这一切的目的是什么?@Ubiquité它叫位域。你能发布一个具体的问题吗?如果你有问题,为什么不测试一下呢?@Philipp:我关心的是,这是否适用于power pc。在windows上运行时,我看到的是位域级别的endianess。所以我不得不更改我的get和set f函数,因此..现在的问题是,所有字段的get和set函数是否也能在power pc上工作?不,类本质上与结构相同。即使您在编译器中启用RTTI?或者有虚拟方法?我的理解是,插入vtab会转移所有内容…@epatel:对不起,我的基本问题,但是可以这个函数在不同平台上都是通用的?编译器的解释也是如此。我还试图提取windows主机上的字段,其中nibble的读取顺序不同。@epatel:虚拟函数和虚拟基类可以(和do)占用额外的空间,但这与struct
与class
无关。使用struct
声明的类也可以有虚拟成员或基类。只要类没有虚拟成员或基类,并且所有数据成员都具有相同的访问控制,在大多数情况下,它可以像C结构一样使用@user434250抱歉,不知道所有平台。但这是我们在将旧的遗留SGI编译器代码移植到intel(Windows Visual Studio和Linux GNU工具)时使用的方法。也许还有更多的东西需要检查,我现在不知道。但这是一个有趣的问题。另一个完全不同的方法是制作一个bitbuffer类,你可以填充并提取它,就像放入(并提取)缓冲区一样每个字段,即bitbuffer是,即我关心的是,这是否适用于power pc。在windows上运行时,我看到endianess处于半字节级别。因此,我必须相应地更改我的get和set函数。现在关心的是,所有字段的get和set函数是否也适用于power pc@Michael:谢谢你提供的信息。just澄清。那么你的建议是,我需要调用hton和ntoh函数作为包装器来获取和设置函数?@user434250-否。我们以“网络”格式传输数据,但我们将其存储在本地的“主机”(也称为“本地”)中当我们接收数据时,我们使用Ntoh将其转换成本地格式,并使用本地格式。当我们要传输它时,我们使用HOTN将其转换成网络格式。@ USE43250-听起来很奇怪,但是C++知道本地的位排序,并且只要本地数据格式,无论是什么“本地”,这些GET/SET函数都将工作。实际上是。(假设它们一开始是正确的)。“x&1”将为您提供最低有效位,无论该位物理存储在内存中的什么位置&(1目前,我正在将输入流键入st_ipv6类..并在同一个流上调用set和get函数。我想您可以将hton/ntoh合并到get/set例程中,但要小心。尤其是对于set例程。Ma