C++ Bigendian/Littleendian混淆

C++ Bigendian/Littleendian混淆,c++,C++,我正在编写用于ipv4的遗留代码。现在,我为ipv6添加了类似的代码。我已经在主机上进行了尝试和测试。但是我担心它是否能在powerpc上工作,因为endianness…代码是从传入流中提取ip头并压缩它。任何注释都会有帮助 class st_ipv6 { //================================================================================================== public: //======

我正在编写用于ipv4的遗留代码。现在,我为ipv6添加了类似的代码。我已经在主机上进行了尝试和测试。但是我担心它是否能在powerpc上工作,因为endianness…代码是从传入流中提取ip头并压缩它。任何注释都会有帮助

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