【问题标题】:Working with individual bytes using unsigned char arrays使用无符号字符数组处理单个字节
【发布时间】:2015-03-30 18:29:27
【问题描述】:

我搜索了很多网站,但似乎找不到任何相关内容。

我希望能够获取每个默认数据类型的单个字节,例如 short、unsigned short、int、unsigned int、float 和 double,并将每个单独的字节信息(二进制部分)存储到每个索引中无符号字符数组。如何实现?

例如:

int main() {
    short sVal = 1;
    unsigned short usVal = 2;
    int iVal = 3;
    unsigned int uiVal = 4;
    float fVal = 5.0f;
    double dVal = 6.0;

    const unsigned int uiLengthOfShort  = sizeof(short);
    const unsigned int uiLengthOfUShort = sizeof(unsigned short);
    const unsigned int uiLengthOfInt    = sizeof(int);
    const unsigned int uiLengthOfUInt   = sizeof(unsigned int);
    const unsigned int uiLengthOfFloat  = sizeof(float);
    const unsigned int uiLengthOfDouble = sizeof(double);

    unsigned char ucShort[uiLengthOfShort];
    unsigned char ucUShort[uiLengthOfUShort];
    unsigned char ucInt[uiLengthOfInt];
    unsigned char ucUInt[uiLengthOfUInt];
    unsigned char ucFloat[uiLengthOfFloat];
    unsigned char ucDouble[uiLengthOfDouble];

    // Above I declared a variable val for each data type to work with
    // Next I created a const unsigned int of each type's size.
    // Then I created unsigned char[] using each data types size respectively
    // Now I would like to take each individual byte of the above val's
    // and store them into the indexed location of each unsigned char array.

    // For Example: - I'll not use int here since the int is 
    // machine and OS dependent. 
    // I will use a data type that is common across almost all machines. 
    // Here I will use the short as my example

    // We know that a short is 2-bytes or has 16 bits encoded
    // I would like to take the 1st byte of this short:
    // (the first 8 bit sequence) and to store it into the first index of my unsigned char[].
    // Then I would like to take the 2nd byte of this short:
    // (the second 8 bit sequence) and store it into the second index of my unsigned char[]. 

    // How would this be achieved for any of the data types?

    // A Short in memory is 2 bytes here is a bit representation of an 
    // arbitrary short in memory { 0101 1101, 0011 1010 }
    // I would like ucShort[0] = sVal's { 0101 1101 } &
    //              ucShort[1] = sVal's { 0011 1010 } 

    ucShort[0] = sVal's First Byte info. (8 Bit sequence)
    ucShort[1] = sVal's Second Byte info. (8 Bit sequence)

    // ... and so on for each data type.

    return 0;
}

【问题讨论】:

  • 你怎么知道没有短是 32 位的系统?
  • 了解工会。不确定“每种默认数据类型的单个字节”是什么意思。
  • 我说在大多数机器上短是 2 个字节。这并不意味着全部,但更可能的是短是 2 字节,然后使用可能是 16 位(2 字节过时)、32 位(x86 上常见 4 字节)和 64 位(64 位机器上常见 8 字节)的整数。
  • @Raw N - 是的,我已经阅读了联合,但这是否也会保留字节顺序,还是必须在不同平台之间进行转换?另外,我想制作一个可以接受任何数据类型变量并执行此操作并返回 unsigned char* 的函数
  • 对齐和顺序取决于系统。

标签: c++ arrays bit-manipulation byte


【解决方案1】:

好的,首先,如果可以避免,请不要这样做。它很危险,并且可能非常依赖于架构。

上面的评论是正确的,联合是最安全的方法,你仍然有字节序问题,是的,但至少你没有堆栈对齐问题(我假设这是网络代码,所以堆栈-alignment 是另一个潜在的架构问题)

这是我发现的最直接的方法:

uint32_t example_int;
char array[4];

//No endian switch
array[0] = ((char*) &example_int)[0];
array[1] = ((char*) &example_int)[1];
array[2] = ((char*) &example_int)[2];
array[3] = ((char*) &example_int)[3];

//Endian switch
array[0] = ((char*) &example_int)[3];
array[1] = ((char*) &example_int)[2];
array[2] = ((char*) &example_int)[1];
array[3] = ((char*) &example_int)[0];

如果您尝试编写跨架构代码,则需要以一种或另一种方式处理字节序问题。我的建议是基于上述方法构建一个短端测试并构建函数来“打包”和“解包”字节数组。需要注意的是,要“解包”一个字节数组,只需颠倒上述赋值语句即可。

【讨论】:

  • 谢谢,但我也发现了这个cplusplus.com/forum/articles/12,它也与我要找的很接近,但不知道字节序或对齐是否仍然是一个问题。
  • 我打算使用这种类型的算法来获取各种数据类型并将它们存储到 unsigned char[] 或 unsigned char* 中,然后将内容保存到二进制文件中。这里没有直接压缩,而是一种将数据打包成一种类型供文件读取器/写入器类使用的方法。文件内容将存储为一堆无符号字符数组,但以字节为单位将是来自游戏引擎的数据,例如位置、像素、玩家等。然后使用此文件的格式跨网络传输将很容易。
【解决方案2】:

最简单的正确方法是:

// static_assert(sizeof ucShort == sizeof sVal);

memcpy( &ucShort, &sVal, sizeof ucShort);

你在cmets中写的东西不正确;除字符类型外,所有类型都有与机器相关的大小。

【讨论】:

    【解决方案3】:

    在 Raw N 的帮助下,通过为我提供了一个网站,我搜索了字节操作并找到了这个线程 - http://www.cplusplus.com/forum/articles/12/,它提供了一个与我正在寻找的类似的解决方案,但是我不得不重复这个处理每种默认数据类型。

    【讨论】:

      【解决方案4】:

      在做了一些测试之后,这是我迄今为止提出的,这取决于机器架构,但要在其他机器上执行此操作,概念是相同的。

      typedef struct packed_2bytes {
          unsigned char c0;
          unsigned char c1;
      } packed_2bytes;
      
      typedef struct packed_4bytes {
          unsigned char c0;
          unsigned char c1;
          unsigned char c2;
          unsigned char c3;
      } packed_4bytes;
      
      typedef struct packed_8bytes {
          unsigned char c0;
          unsigned char c1;
          unsigned char c2;
          unsigned char c3;
          unsigned char c4;
          unsigned char c5;
          unsigned char c6;
          unsigned char c7;
      } packed_8bytes;
      
      typedef union {
          short s;
          packed_2bytes bytes;
      } packed_short;
      
      typedef union {
          unsigned short us;
          packed_2bytes bytes;
      } packed_ushort;
      
      typedef union { // 32bit machine, os, compiler only
          int i;
          packed_4bytes bytes;
      } packed_int;
      
      typedef union { // 32 bit machine, os, compiler only
          unsigned int ui;
          packed_4bytes bytes;
      } packed_uint;
      
      typedef union { 
          float f;
          packed_4bytes bytes;
      } packed_float;
      
      typedef union {
          double d;
          packed_8bytes bytes;
      } packed_double;
      

      没有实现只使用这些类型的声明或定义。我确实认为它们应该包含正在使用的任何字节序,但是使用它们的人必须提前知道这一点,就像知道每种默认类型的机器架构大小一样。我不确定有符号 int 是否会因为 one's、two's 恭维或有符号位实现而出现问题,但也可能需要考虑。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-30
        • 1970-01-01
        • 2017-12-03
        • 2018-05-25
        • 2018-04-07
        • 2013-07-11
        • 1970-01-01
        相关资源
        最近更新 更多