简体   繁体   English

C ++中的位移

[英]Bit shifting in C++

I have the following struct: 我有以下结构:

struct SysData
{ 
        // Topic (32 bits)
        UTL_UINT16_Tdef SystemID:11;    // set to decimal 25
        UTL_UINT16_Tdef TypeID:5;       // set to 2 (telemetry type)
        UTL_UINT16_Tdef ContentID;      // set to decimal 1234
}

SysData MsgHdr;
MsgHdr.SystemID   = 25;
MsgHdr.TypeID     = 2;
MsgHdr.ContentID  = 0;

If I do something like this: 如果我做这样的事情:

    unsigned int a;
    memcpy(&a, &MsgHdr, sizeof(MsgHdr));
    headerInfo[0] = a & 0x7FF;
    headerInfo[1] = (a >> 16) & 31;
    headerInfo[2] = (a >> 21) & 0xFFFF;

headerInfo[0] should have the value 25, but it has 36. What am I doing wrong? headerInfo [0]应该具有值25,但它有36.我做错了什么?

You shouldn't guess on the internal representation of SysData.Compiler may choose to pack bit fields together or not, to align them left or right, etc. It can even choose to map them to 32 bits integer for performances issue. 您不应该猜测SysData的内部表示。编译器可能选择将位字段打包在一起或不打包,将它们左右对齐等。它甚至可以选择将它们映射到32位整数以解决性能问题。 You just can't know. 你只是不知道。 The unused part of the bitfield may contain garbage and it's probably where you got your 36. 位域的未使用部分可能包含垃圾,它可能就在你获得36的位置。

It's strange, but not really hard to check. 这很奇怪,但不是很难检查。 Change your 25 to other values and see what you get. 将您的25改为其他值,看看你得到了什么。

However, memcopying your structure to some unsigned int is probably not a good idea. 但是,将结构存储到某些unsigned int可能不是一个好主意。 Why don't you access bitfield directly ? 你为什么不直接访问bitfield? Like in headerInfo[0] = MsgHdr.SystemID; 就像在headerInfo[0] = MsgHdr.SystemID; that's what bitfields are for. 这就是bitfields的用途。 In your example the memcopy is just a loss of time (and also dangerous as you can see). 在你的例子中,memcopy只是一个时间的损失(也是危险的,你可以看到)。

The implementation of bitfields is not defined and varies based on what compiler you use. 未定义位域的实现,并根据您使用的编译器而有所不同。

(EDIT: Ignore my incorrect guess on where the 36 is coming from) (编辑:忽略我对36来自哪里的错误猜测)

I can't think of how you would get to 36, but with bitfields, I would strongly recommend reading them using plain read access functions instead of shifting them around, ie 我想不出你会如何达到36,但是对于bitfields,我强烈建议使用普通读取访问函数来读取它们,而不是将它们移动,即

SysData *pSysData = (SysData *) &MsgHdr;
headerInfo[0] = pSysData->ContentID;

Btw, I don't understand your example. 顺便说一句,我不明白你的例子。 You're saying headerInfo[0] should be 25. But shouldn't it be 0? 你说headerInfo [0]应该是25.但不应该是0吗? Your example says ContentID is 0, and I figured that's what you're trying to read there. 你的例子说ContentID是0,我想你正在尝试阅读那里。

除了可能的endian问题或打包问题之外,headerInfo [1]的转换不应该是11而headerInfo [2]应该是16吗?

Like EboMike, can't figure where you're getting 36 像EboMike一样,无法想象你得到的地方36

a) decimal 25 = 00000011001 b) decimal 2 = 00010 c) decimal 1234 = 000010011010010 a)十进制25 = 00000011001 b)十进制2 = 00010 c)十进制1234 = 000010011010010

So the different combinations are: 所以不同的组合是:

  • abc = 0000001[100100]010000010011010010 abc = 0000001 [100100] 010000010011010010
  • acb = 0000001[100100]00100110[100100]0010 acb = 0000001 [100100] 00100110 [100100] 0010
  • bac = 000100000001[100100]0010011010010 bac = 000100000001 [100100] 0010011010010
  • bca = 0001000001001101001000000011001 bca = 0001000001001101001000000011001
  • cab = 0000100110[100100]000001[100100]010 cab = 0000100110 [100100] 000001 [100100] 010
  • cba = 0000100110[100100]001000000011001 cba = 0000100110 [100100] 001000000011001

Nothing there ends in the required 100100 bit sequence, so unless the struct is actually being stored over two uints or something wacky is going on, I'm lost. 在所需的100100位序列中没有任何结束,所以除非结构实际上存储在两个uint之外或者某些古怪的东西正在发生,否则我迷失了。 Load up into a debugger and see what a actually stores. 加载到调试器中,看看实际存储的内容。

If I do this: 如果我这样做:

#include <stdio.h>
#include <memory.h>

typedef unsigned short UTL_UINT16_Tdef;

struct SysData { 
  // Topic (32 bits)
  UTL_UINT16_Tdef SystemID:11;    // set to decimal 25
  UTL_UINT16_Tdef TypeID:5;       // set to 2 (telemetry type)
  UTL_UINT16_Tdef ContentID;      // set to decimal 1234
};

int main() {

  SysData MsgHdr;

  MsgHdr.SystemID   = 33;
  MsgHdr.TypeID     = 22;
  MsgHdr.ContentID  = 11;

  unsigned int a;
  memcpy(&a, &MsgHdr, sizeof(MsgHdr));

/*
  headerInfo[0] = a & 0x7FF;
  headerInfo[1] = (a >> 16) & 31;
  headerInfo[2] = (a >> 21) & 0xFFFF;
*/

  printf( "%08X %i\n", a, sizeof(SysData) );

  printf( "0: %i\n", a & 0x7FF );
  printf( "1: %i\n", (a >> 11) & 31 );
  printf( "2: %i\n", (a >> 16) & 0xFFFF );

}

I get expected results, and codepad does too - http://codepad.org/XNm0Yp90 我得到了预期的结果,而且键盘也是如此 - http://codepad.org/XNm0Yp90

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM