【问题标题】:Endianness Work-around Needed需要字节序解决方法
【发布时间】:2013-07-03 12:53:19
【问题描述】:

考虑以下代码:

#include "stdio.h"

typedef struct CustomStruct
{
  short Element1[10];
}CustomStruct;

void F2(char* Y)
{
  *Y=0x00;
  Y++; 
  *Y=0x1F;    
}

void F1(CustomStruct* X)
{
  F2((char *)X);
  printf("s = %x\n", (*X).Element1[0]);
}

int main(void)
{
  CustomStruct s;
  F1(&s);

  return 0;
}

在运行时,调用函数F1结束时,使用不同的编译器会得到不同的结果。

(*X).Element1[0] = 0x1f00 在某些编译器中,(*X).Element1[0] = 0x001f 在另一个编译器中。

我很清楚这是一个字节序问题。

是否有任何编译器选项或变通方法可供使用,以便我得到 (*X).Element1[0] = 0x001f 而不管使用的编译器?

【问题讨论】:

  • 向我们展示您如何填充Element1
  • 对不起,我没明白你的意思。你的意思是你需要F2的实际身体吗?我认为它没用,因为我保证在 F2 结束时你有 Y[0]=0x00 和 Y[1]=0x1F。
  • 您正在尝试提供该保证。我们正在尝试向您展示如何操作,但除非您向我们提供真正的代码,否则我们只能猜测您在做什么。
  • 我已经更新了代码,以便我们更好地了解彼此:)
  • 它实际上在我的英特尔系统上打印1f00,但是好的,我想我现在知道了。

标签: c++ c pointers endianness cpu-architecture


【解决方案1】:

Endianness 不是编译器问题,甚至不是操作系统问题,而是平台问题。字节序没有编译器选项或“解决方法”。然而,有一些转换例程,以便您可以标准化存储数据的字节顺序。

ntoh 例程documented here 会将指向的字节重新排序,从网络顺序(大端)到主机顺序(大或小,取决于主机的类型)。还有hton 的函数方向相反,从主机顺序到网络顺序。

如果您想规范化存储在数据结构中的字节,则需要在存储数据或尝试读取数据时自己进行。

以下是我为 ntohxhtonx 编写的函数模板,它们概括了数据存储的类型,无论是 2 字节、4 字节还是 8 字节类型:

template<class Val> inline Val ntohx(const Val& in)
{
    char out[sizeof(in)] = {0};
    for( size_t i = 0; i < sizeof(Val); ++i )
        out[i] = ((char*)&in)[sizeof(Val)-i-1];
    return *(reinterpret_cast<Val*>(out));
}

template<> inline unsigned char ntohx<unsigned char>(const unsigned char & v )
{
    return v;
}
template<> inline uint16_t ntohx<uint16_t>(const uint16_t & v)
{
    return ntohs(v);
}

template<> inline uint32_t ntohx<uint32_t>(const uint32_t & v)
{
    return ntohl(v);
}

template<> inline uint64_t ntohx<uint64_t>(const uint64_t & v)
{
    uint32_t ret [] =
    {
        ntohl(((const uint32_t*)&v)[1]),
        ntohl(((const uint32_t*)&v)[0])
    };
    return *((uint64_t*)&ret[0]);
}
template<> inline float ntohx<float>(const float& v)
{
    uint32_t const* cast = reinterpret_cast<uint32_t const*>(&v);
    uint32_t ret = ntohx(*cast);
    return *(reinterpret_cast<float*>(&ret));
};

template<class Val> inline Val htonx(const Val& in)
{
    char out[sizeof(in)] = {0};
    for( size_t i = 0; i < sizeof(Val); ++i )
        out[i] = ((char*)&in)[sizeof(Val)-i-1];
    return *(reinterpret_cast<Val*>(out));
}

template<> inline unsigned char htonx<unsigned char>(const unsigned char & v )
{
    return v;
}
template<> inline uint16_t htonx<uint16_t>(const uint16_t & v)
{
    return htons(v);
}

template<> inline uint32_t htonx<uint32_t>(const uint32_t & v)
{
    return htonl(v);
}

template<> inline uint64_t htonx<uint64_t>(const uint64_t & v)
{
    uint32_t ret [] =
    {
        htonl(((const uint32_t*)&v)[1]),
        htonl(((const uint32_t*)&v)[0])
    };
    return *((uint64_t*)&ret[0]);
}
template<> inline float htonx<float>(const float& v)
{
    uint32_t const* cast = reinterpret_cast<uint32_t const*>(&v);
    uint32_t ret = htonx(*cast);
    return *(reinterpret_cast<float*>(&ret));
};

【讨论】:

  • 当然,ntoh/hton 仅用于保证一种表示将采用 Big Endian,并且无论字节顺序如何,您的机器都可以使用一种表示;它没有提供直接机制来保证一种表示将采用 Little Endian。
  • @Medinoc:没错,没错。
【解决方案2】:

如果F2() 正在接收char *,那么它一定是在做一些非常奇怪的事情以引起与字节序相关的问题。

这些仅在一次访问多个char 时发生,除非它在被破坏时手动执行此类访问。是将它的论点转换回short * 还是什么?

简而言之,显示更多代码。

【讨论】:

  • 我现在添加了问题的编译代码 :) 如果你尝试过,它会打印 0x1f00。但是当将此代码刷新到嵌入式目标并调试(uController)时(*X).Element1[0] = 0x001f.
猜你喜欢
  • 2022-10-15
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
相关资源
最近更新 更多