940317 - 位域的奇怪行为 [英] 940317 - Weird behavior of bitfields

查看:104
本文介绍了940317 - 位域的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码会产生5,3,而我希望它会产生0,2。从本质上讲,这就是我们使用位域的原因!

 void f2()
{
struct s1
{
short a: 9;
char b:4;
};
union s2
{
s1 c;
短d;
};

s2 e;
e.c.b = 5;
e.d = 0; //我希望& b的c都得到零
cout<< (int)e.c.b; //但是b不是

cout<< ,<< sizeof(s1)<< ENDL; //因为d不包括b
}



任何想法?

解决方案

很多bitfields实现的各个方面都依赖于编译器,这在打包值时会产生一些问题,因为布局是未定义的。

无论如何,许多编译器使用的一个主要规则是区分数据类型以进行打包。在同一类型中打包的含义,如果类型更改也字段启动新内存。即如果您将声明更改为:

  struct  s1 
{
short a: 9 ;
简短 b: 4 ;
};



这将为您提供输出0,2,如您所料。

在原始声明中,编译器实例化一个简短的仅使用9位,然后仅使用4位为第二个变量实例化一个char。

这解释了为什么你得到3个字节的大小,但仍然没有解释为什么你不能为零变量值。所以我决定在Visual Studio中进行调试,然后进入汇编以了解奇怪行为的原因,然后我找到了它。内存布局为:

 +  -  +  -  +  -  +  -  +  -  +  -  +  -  +  -  + 
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ - + - + - + - + - + - + - + - +
\ _______ _______ /
v
+ ------ + ---- - > a = 9bits:低位8位加高位字节
^
+ - + - + - + - + - + - + - + - +
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | (从1到7不使用的位)
+ - + - + - + - + - + - + - + - +
+ - + - + - + - + - + - + - + - + \
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | \(未使用位4到7)
+ - + - + - + - + - + - + - + - + |
\ ___ ___ / |
v> d =这两个字节用于短
b = 4位|在工会。
+ - + - + - + - + - + - + - + - + |
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | /
+ - + - + - + - + - + - + - + - + /



这解释了所有。

使用位字段时,您选择一种类型来定义要使用的内存空间,即声明将共享该空间的所有变量。



  struct  MyStruct 
{
char a: 2 ;
char b: 2 ;
char c: 1 ;
char d: 3 ;
int e: 8 ;
int f: 7 ;
int g: 17 ;
}



将占用5个字节,第一个用于a,b,c和d。然后下面的int(4个字节)将保存e,f和g。


你必须理解C中的联合。这是教程。成员共享内存,所以你可以做奇怪和有问题的事情。



短片只有2个字节。

并且 sizeof 返回字节,因此(9 + 4)/ 8和对齐。

The following code results in "5,3", while i expect it to result in "0,2". Essentially, this is why we use bitfields!

void f2()
{
	struct s1
	{
		short a:9;
		char b:4;
	};
	union s2
	{
		s1 c;
		short d;
	};

	s2 e;
	e.c.b = 5;
	e.d = 0;  // i expect that a & b of c both get zero
	cout << (int) e.c.b;  // but b doesn't

	cout << "," << sizeof(s1) << endl;  // because d doesn't cover b
}


any idea?

解决方案

Many aspects of bitfields implementation are compiler dependent, and this creates some problem when packing values because the layout is undefined.
Anyway one main rule that the many compiler use is to differentiate between data types for packing. Meaning that is packed while in the same type, if the type change also fields start a new memory. I.e. if you change your declaration as:

struct s1
{
    short a:9;
    short b:4;
};


this will give you an output 0,2 as you would expect.
In the original declaration the compiler instantiate a short using only 9 bits, then instantiate a char, using only 4 bits, for the second variable.
This explain why you get a size of 3 bytes, but still don't explain why you cannot zero the variable value. So I decided to make a debug tour in Visual Studio going into assembly to understand the reason for the strange behavior, and I found it. The memory layout is:

+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
\_______ _______/
        v
 +------+-----> a = 9bits: 8 from the lower one plus 1 from higher byte
 ^
+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7| (bits from 1 to 7 not used)
+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+\
|0|1|2|3|4|5|6|7| \ (bits 4 to 7 not used)
+-+-+-+-+-+-+-+-+  |
\___ ___/          |
    v              > d = These 2 bytes are used for the short
 b = 4 bits        |     in the union.
+-+-+-+-+-+-+-+-+  |
|0|1|2|3|4|5|6|7| /
+-+-+-+-+-+-+-+-+/


And this explain all.
When using the bit-fields you choose a type to define the memory space to use, that declare all variables that will share that space.
I.e.

struct MyStruct
{
  char a:2;
  char b:2;
  char c:1;
  char d:3;
  int  e:8;
  int  f:7;
  int  g:17;
}


Will occupy 5 bytes, the first for a, b, c, and d. Then the following int (4 bytes) will hold e, f and g.


You must understand unions in C. Here is a tutorial. The member share memory, so you can do strange and buggy things with.

A short is only 2 bytes.
And sizeof return bytes, so (9+4) / 8 and alignment.


这篇关于940317 - 位域的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆