【问题标题】:Testing C++ code for endian-independence测试 C++ 代码的字节序无关性
【发布时间】:2011-06-20 14:24:24
【问题描述】:

如何测试或检查 C++ 代码的字节序无关性?它已经实现了,我只想验证它在 little-endian 和 big-endian 平台上都可以工作。

我可以编写单元测试并在目标平台上运行它们,但我没有硬件。也许是模拟器?

是否可以进行编译时检查?

【问题讨论】:

  • @0A0D,这不是骗局。那个问题是关于如何检测当前平台的字节顺序。 OP 想检查他的代码是否在 BE 和 LE 平台上都能正常工作。
  • @0A0D:这与检测平台的字节顺序无关。问题是如何确定某些给出的代码是否取决于字节序。
  • @Chris Google 首页上“测试字节序”的结果都没有解决我的问题。
  • @Chris:不,克里斯。 Google 知道 是一名开发人员,并且顶部链接(我所看到的所有内容,我查看了列表)都是关于确定字节序,而不是测试代码字节序安全性
  • @0A0D 我添加了一些说明,我希望验证,而不是实施。

标签: c++ testing endianness


【解决方案1】:

如果您可以使用基于 x86 的 Mac,那么您可以利用 Mac OS X 内置 PowerPC 仿真以及对 x86(小端)和 PowerPC(大端)的开发工具支持这一事实。这使您能够在同一平台上编译和运行大端和小端可执行文件,例如

$ gcc -arch i386 foo.c -o foo_x86 # build little endian x86 executable
$ gcc -arch ppc foo.c -o foo_ppc  # build big endian PowerPC executable

构建了 big endian 和 little endian 可执行文件后,您可以运行任何可用的单元测试,这将捕获一些与字节序相关的问题,您还可以比较可执行文件生成的任何数据(文件、网络数据包,无论如何) - 这显然应该匹配。

【讨论】:

  • 如果您没有 Mac,该问题的解决方案相当昂贵。投反对票不是我的。
  • @Kirill(和匿名投票者):请注意,我特别说过“如果您可以访问 Mac” - 有很多方法可以访问 Mac 进行一段时间的测试,而无需实际购买一台(尽管已经指出,便宜的二手 Mac Mini 在 eBay 上的成本很低)。
  • @Paul:你知道是否有可能在 x86 机器上为 PPC 架构编译逆向?也许我没说对……
  • @Paul:另外,请参阅 OP 的编辑。使用您的方法,他如何验证?
  • 访问 Mac 的最便宜的方式可能就是去 Apple Store 商店。你可以在那里试用 Mac 并编译你的东西。只要确保员工看不到你。 :)
【解决方案2】:

您可以使用qemu 以相反的字节序设置执行环境。例如,如果您可以访问 little-endian amd64 或 i386 硬件,您可以设置 qemu 以模拟 PowerPC Linux 平台,并在那里运行您的代码。

【讨论】:

    【解决方案3】:

    【讨论】:

      【解决方案4】:

      我建议采用一种可以完全避免问题的编码技术。

      首先,您必须了解在哪种情况下会出现字节序问题。然后要么找到一种与字节顺序无关的方式来编写它,要么隔离代码。

      例如,可能出现字节顺序问题的典型问题是当您使用内存访问或联合来挑选较大值的部分时。具体来说,避免:

      long x;
      ...
      char second_byte = *(((char *)&x) + 1);
      

      改为:

      long x;
      ...
      char second_byte = (char)(x >> 8)
      

      串联,这是我的最爱之一,因为许多人倾向于认为您只能使用奇怪的技巧来做到这一点。不要这样做:

      union uu
      {
        long x;
        unsigned short s[2];
      };
      union uu u;
      u.s[0] = low;
      u.s[1] = high;
      long res = u.x;       
      

      改为写:

      long res = (((unsigned long)high) << 16) | low
      

      【讨论】:

        【解决方案5】:

        我可以编写单元测试并在目标平台上运行它们,但我没有硬件。

        您可以设置您的设计,以便单元测试易于运行,而无需实际拥有硬件。您可以使用依赖注入来做到这一点。我可以通过提供我正在测试的代码与之对话的基接口类来抽象出硬件接口之类的东西。

        class IHw
        {
        public:
            virtual void SendMsg1(const char* msg, size_t size) = 0;
            virtual void RcvMsg2(Msg2Callback* callback) = 0;
             ...
        };
        

        然后我可以有实际与硬件对话的具体实现:

        class CHw : public IHw
        {
        public:
            void SendMsg1(const char* msg, size_t size);
            void RcvMsg2(Msg2Callback* callback);
        };
        

        我可以制作一个测试存根版本:

        class CTestHw : public IHw
        {
        public:
            void SendMsg1(const char* msg, size_t);
            void RcvMsg2(Msg2Callback* callback);
        };
        

        然后我的真实代码可以使用具体的Hw,但我可以用CTestHw在测试代码中模拟它。

        class CSomeClassThatUsesHw
        {
        public:
           void MyCallback(const char* msg, size_t size)
           {
               // process msg 2
           }
           void DoSomethingToHw()
           {
               hw->SendMsg1();
               hw->RcvMsg2(&MyCallback);
           }
        private:
            IHw* hw; 
        }
        

        【讨论】:

        • 有时我可以编写我的代码,使其不依赖于特定的字节顺序,并且可以在所有硬件平台上运行。在可能的情况下,我更喜欢它而不是特定于硬件的实现,因为这意味着维护更少的代码。
        • 当然,但是依赖注入你的字节序转换??是不是有点远?
        【解决方案6】:

        IMO,唯一接近正确的答案是 Martin 的。如果您不与二进制文件中的其他应用程序通信或读取/写入二进制文件,则无需解决字节顺序问题。如果所有持久数据都是字符流的形式(例如数据包是 ASCII,输入文件是 ASCII,输出文件是 ASCII),那么在小端机器中发生的事情会留在小端机器中。

        我将此作为答案而不是对 Martin 的答案的评论,因为我建议您考虑做一些与 Martin 提议的不同的事情。鉴于占主导地位的机器架构是小端,而网络顺序是大端,如果您可以完全避免字节交换,则会出现许多优势。解决方案是让您的应用程序能够处理错误的字节序输入。使通信协议以某种机器身份数据包开始。有了这些信息,您的程序可以知道它是否必须对后续传入的数据包进行字节交换或保持原样。如果您的二进制文件的标题有一些指示符可以让您确定这些文件的字节顺序,则同样的概念也适用。有了这种架构,您的应用程序可以以原生格式编写,并且可以知道如何处理非原生格式的输入。

        嗯,差不多。二进制交换/二进制文件还有其他问题。一个这样的问题是浮点数据。 IEEE 浮点标准没有说明如何存储浮点数据。它没有说明字节顺序,没有说明有效数是在指数之前还是之后,也没有说明存储的指数和有效数的存储位顺序。这意味着您可以拥有两台具有相同字节顺序的不同机器,它们都遵循 IEEE 标准,但在将浮点数据作为二进制通信时仍然会遇到问题。

        另一个今天不那么普遍的问题是字节序不是二进制的。除了大和小,还有其他选择。幸运的是,计算机以 2143 顺序(而不是 1234 或 4321 顺序)存储东西的时代已经远远落后,除非您处理嵌入式系统。

        底线: 如果您正在处理一组近乎同质的计算机,只有一个或两个古怪(但不是太古怪),您可能需要考虑避免网络顺序。如果域有多种架构的机器,其中一些很奇怪,你可能不得不求助于网络秩序的通用语言。 (但请注意,这种通用语言并不能完全解决浮点问题。)

        【讨论】:

          【解决方案7】:

          我个人使用 Travis 来测试我在 github 上托管的软件,它支持在多种架构 [1] 上运行,包括大端的 s390x。

          我只需要将它添加到我的.travis.yml

          arch:
            - amd64
            - s390x  # Big endian arch
          

          这可能不是唯一提出此建议的 CI,但那是我已经在使用的 CI。我在这两个系统上都运行了单元测试和集成测试,这让我有理由相信无论字节序如何,它都能正常工作。

          虽然这不是灵丹妙药,但我也希望有一种简单的方法来手动测试它,以确保没有隐藏的错误(例如,我使用的是 SDL,颜色可能是错误的。我正在使用屏幕截图来验证输出,但用于截屏的代码可能会出现补偿显示问题的错误,因此测试可能会在显示错误的情况下通过)。

          [1]https://blog.travis-ci.com/2019-11-12-multi-cpu-architecture-ibm-power-ibm-z

          【讨论】:

            猜你喜欢
            • 2012-12-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-12-09
            • 1970-01-01
            • 2010-09-09
            • 1970-01-01
            • 2018-02-10
            相关资源
            最近更新 更多