2012-12-19 33 views
4

我想知道为什么位域可以与工会/结构一起工作,但不能和像intshort这样的正常变量一起工作。
这工作:为什么正常变量不允许位域?

struct foo { 
    int bar : 10; 
}; 

但这种失败:

int bar : 10; // "Expected ';' at end of declaration" 

为什么这个功能仅在工会/结构,而不是与变量可用?技术不一样吗?


编辑:

如果将允许你能与例如3个字节的变量,而不每次使用结构/联合成员。这是我如何与一个结构:

struct int24_t { 
    int x : 24 __attribute__((packed)); 
}; 

struct int24_t var; // sizeof(var) is now 3 
// access the value would be easier: 
var.x = 123; 
+4

呃,因为它没有意义。 – 2012-12-19 18:13:56

+3

@ H2CO3这并不能帮助回答这个问题。你想说明为什么它在一个案件中是有道理的,但不是另一个案件中的道理? (我相信你有理由发表你的评论,我只是想知道它是什么。) –

+2

@ap。当然。位域用于在结构的成员之间分割/共享位。如果只有一个变量,并且没有(连续的)字段(在结构中),这是不合理的/有意义的。 – 2012-12-19 18:16:56

回答

7

这是一个主观问题,“规范为什么这么说?”但我会把它拍下来。

与其他持续时间(静态持续时间,线程持续时间和分配持续时间)相比,函数中的变量通常具有“自动”存储。

在一个结构中,你明确地定义了一些对象的内存布局。但是在函数中,编译器自动以某种未指定的方式将变量分配给变量。下面是一个问题:x占用了多少字节?

// sizeof(unsigned) == 4 
unsigned x; 

这可能需要4个字节,或它可能需要长达8,或12,或0,或者它可以得到安置在三个不同的寄存器的同时,或在堆栈和寄存器,或它可以在堆栈中获得四个位置。

问题是编译器正在为你做分配。既然你没有做栈的布局,你不应该指定位宽。

扩展的讨论:位域实际上有点特殊。该规范指出,相邻的位域被打包到同一个存储单元中。位域不是实际的对象。

  1. 你不能sizeof()位字段。

  2. 你不能malloc()位字段。

  3. 你不能&addressof位字段。

所有这些东西你可以用C中的对象来做,但不能用位域。位域是一种特殊的东西,仅用于结构和其他地方。

关于int24_t(最新版):它适用于某些架构,但不适用于其他架构。它甚至不是便携式

typedef struct { 
    int x : 24 __attribute__((packed)); 
} int24_t; 

在Linux ELF/64,OS X/86,OS X/64,sizeof(int24_t) == 3。但在OS X/PowerPC上,sizeof(int24_t) == 4

注意代码GCC生成装载int24_t基本上等同于这样:

int result = (((char *) ptr)[0] << 16) | 
      (((unsigned char *) ptr)[1] << 8) | 
      ((unsigned char *)ptr)[2]; 

它在x64 9分的说明,只是加载一个值。

+0

sizeof(int24_t)将是3 – vromanov

+0

@vromanov:错了。在通用体系结构上使用上面的声明'sizeof(int24_t)== 4'。 –

+0

请做测试!在Centos 6.5 x64(gcc)sizeof(int24_t)== 3 – vromanov

1

因为它没有意义。位域声明用于共享和重新组织struct的字段之间的位。如果你没有成员,只有一个变量,它的大小是恒定的(这是实现定义的),例如,将一个char(几乎可以肯定是8位宽)声明为一个或两个位变量是矛盾的。

3

结构或联合的成员之间有其存储位置之间的关系。由于严格限制布局,编译器无法以聪明的方式对其进行重新排序或打包;基本上编译器在布局结构方面的唯一自由就是可以自由添加超出对齐所需的额外填充量。 Bitfields允许您手动通过承诺(1)您不需要这些成员的地址,并且(2)您不需要将值存储在特定的有限范围之外。

如果你谈论的是单个变量而不是结构成员,那么在抽象机器中他们有它们的存储位置之间没有关系。如果它们是函数中的本地自动变量,并且它们的地址永远不会被获取,那么编译器可以自由地将它们保存在寄存器中,或者将它们包装在内存中,但它喜欢。手动向编译器提供这些提示几乎没有任何好处。

0

如果一个人有一个结构QBLOB其中包含结合了四个2位位域到单个字节,每一个结构被用作与简单包含unsigned char类型的四个字段的结构体相比,将代表三个字节的时间节省。如果声明一个数组QBLOB myArray[1000000],这样一个数组只需要1,000,000字节;如果QBLOB是一个包含四个unsigned char字段的结构,则它将需要更多300,000字节。因此,使用位域的能力可能会节省大量内存。相比之下,在大多数体系结构中,声明简单变量为最佳大小的位域类型与声明它为最小合适的标准整数类型相比,可以节省至多15位。由于访问位域通常比访问标准整型变量需要更多的代码,因此很少有情况下将各个变量声明为位域会提供任何优势。但是,这个原理有一个明显的例外:一些体系结构包括可以设置,清除和测试各个位的功能,这些功能比读取和写入字节更有效。某些此类体系结构的编译器包括bit类型,并将该类型的八个变量打包到每个存储字节中。这些变量通常局限于静态或全局范围,因为处理它们的专用指令可能会限制使用某些内存区域(链接器可以确保将这些变量放在必须去的地方)。

0

全部对象必须占用一个或多个连续字节或字,但位域不是对象;它只是一个用户友好的掩饰单词中位的方法。包含位域的struct必须占用整数个字节或字;编译器只需添加必要的填充以避免位域大小不合计为完整的单词。

有没有技术为什么你不能扩展C语法来定义结构(AFAIK)之外的位域,但它们对涉及的工作量是有问题的。

相关问题