简体   繁体   English

为什么我不能将位域声明为自动变量?

[英]Why can't I declare bitfields as automatic variables?

I want to declare a bitfield with the size specified using the a colon (I can't remember what the syntax is called). 我想声明一个使用冒号指定大小的位域(我不记得语法是什么)。 I want to write this: 我想写这个:

void myFunction() 
{   
  unsigned int thing : 12;
  ...
}

But GCC says it's a syntax error (it thinks I'm trying to write a nested function). 但是GCC说这是一个语法错误(它认为我正在尝试编写一个嵌套函数)。 I have no problem doing this though: 我这样做没有问题:

struct thingStruct
{
  unsigned int thing : 4;
};

and then putting one such struct on the stack 然后将一个这样的结构放在堆栈上

void myFunction() 
{   
  struct thingStruct thing;
  ...
}

This leads me to believe that it's being prevented by syntax, not semantic issues. 这让我相信它被语法阻止,而不是语义问题。

So why won't the first example work? 那么为什么第一个例子不起作用呢? What am I missing? 我错过了什么?

The first example won't work because you can only declare bitfields inside structs. 第一个示例不起作用,因为您只能在结构中声明位域。 This is syntax, not semantics, as you said, but there it is. 正如你所说,这是语法,而不是语义,但它就是这样。 If you want a bitfield, use a struct. 如果需要位域,请使用结构。

Why would you want to do such a thing? 你为什么要做这样的事情? A bit field of 12 would on all common architectures be padded to at least 16 or 32 bits. 所有常见架构上的12位字段将被填充到至少16或32位。

If you want to ensure the width of an integer variable use the types in inttypes.h , eg int16_t or int32_t . 如果要确保整数变量的宽度,请使用inttypes.h的类型,例如int16_tint32_t

As others have said, bitfields must be declared inside a struct (or union , but that's not really useful). 正如其他人所说,必须在struct (或union内声明位域,但这并不是真的有用。 Why? 为什么? Here are two reasons. 这有两个原因。

  • Mainly, it's to make the compiler writer's job easier. 主要是,它使编译器编写器的工作更容易。 Bitfields tend to require more machine instructions to extract the bits from the bytes. 位域往往需要更多的机器指令来从字节中提取位。 Only fields can be bitfields, and not variables or other objects, so the compiler writer doesn't have to worry about them if there is no . 只有字段可以是位域,而不是变量或其他对象,因此如果没有,编译器编写者不必担心它们. or -> operator involved. ->涉及运算符。

  • But, you say, sometimes the language designers make the compiler writer's job harder in order to make the programmer's life easier. 但是,你说,有时候语言设计师会让编译器作者的工作变得更加困难,以使程序员的生活更轻松。 Well, there is not a lot of demand from programmers for bitfields outside struct s. 那么,程序员对struct s之外的位域的要求并不高。 The reason is that programmers pretty much only bother with bitfields when they're going to cram several small integers inside a single data structure. 原因是当程序员要在单个数据结构中塞入几个小整数时,他们几乎只会烦扰位域。 Otherwise, they'd use a plain integral type. 否则,他们使用普通整数类型。

Other languages have integer range types, eg, you can specify that a variable ranges from 17 to 42. There isn't much call for this in C because C never requires that an implementation check for overflow. 其他语言具有整数范围类型,例如,您可以指定变量范围从17到42.在C中没有太多要求,因为C从不要求执行检查溢出。 So C programmers just choose a type that's capable of representing the desired range; 所以C程序员只需选择一种能够代表所需范围的类型; it's their job to check bounds anyway. 无论如何,检查边界是他们的工作。

C89 (ie, the version of the C language that you can find just about everywhere) offers a limited selection of types that have at least n bits . C89(即您可以在任何地方找到的C语言版本)提供了至少有n位的有限类型选择。 There's unsigned char for 8 bits, unsigned short for 16 bits and unsigned long for 32 bits (plus signed variants). 8位为unsigned char ,16位为unsigned short ,32位为unsigned long (加上有符号变量)。 C99 offers a wider selection of types called uint_least8_t , uint_least16_t , uint_least32_t and uint_least64_t . C99提供了更广泛的类型选择,称为uint_least8_tuint_least16_tuint_least32_tuint_least64_t These types are guaranteed to be the smallest types with at least that many value bits. 这些类型保证是至少具有多个值位的最小类型。 An implementation can provide types for other number of bits, such as uint_least12_t , but most don't. 实现可以提供其他位数的类型,例如uint_least12_t ,但大多数不能。 These types are defined in <stdint.h> , which is available on many C89 implementations even though it's not required by the standard. 这些类型在<stdint.h>中定义,即使标准不需要,也可以在许多C89实现中使用。

Bitfields provide a consistent syntax to access certain implementation-dependent functionality. 位域提供一致的语法来访问某些依赖于实现的功能。 The most common purpose of that functionality is to place certain data items into bits in a certain way, relative to each other . 该功能的最常见目的是以某种方式将某些数据项相对于彼此放置到位中。 If two items (bit-fields or not) are declared as consecutive items in a struct, they are guaranteed to be stored consecutively. 如果在结构中将两个项(位字段或非字段)声明为连续项,则保证它们连续存储。 No such guarantee exists with individual variables, regardless of storage class or scope. 无论存储类别或范围如何,单个变量都不存在此类保证。 If a struct contains: 如果结构包含:

struct foo {
  unsigned bar: 1;
  unsigned boz: 1;
};

it is guaranteed that bar and boz will be stored consecutively (most likely in the same storage location, though I don't think that's actually guaranteed). 保证bar和boz将连续存储(很可能在同一存储位置,但我不认为实际上是有保证的)。 By contrast, 'bar' and 'boz' were single-bit automatic variables, there's no telling where they would be stored, so there'd be little benefit to having them as bitfields. 相比之下,'bar'和'boz'是单位自动变量,没有人知道它们将被存储在何处,因此将它们作为位域进行处理几乎没有什么好处。 If they did share space with some other variable, it would be hard to make sure that different functions reading and writing different bits in the same byte didn't interfere with each other. 如果它们确实与其他变量共享空间,则很难确保在同一字节中读取和写入不同位的不同函数不会相互干扰。

Note that some embedded-systems compilers do expose a genuine 'bit' type, which are packed eight to a byte. 请注意,某些嵌入式系统编译器确实暴露了一个真正的“位”类型,它们打包为8个字节。 Such compilers generally have an area of memory which is allocated for storing nothing but bit variables, and the processors for which they generate code have atomic instructions to test, set, and clear individual bits. 这样的编译器通常具有存储器区域,其被分配用于仅存储位变量,并且它们生成代码的处理器具有用于测试,设置和清除各个位的原子指令。 Since the memory locations holding the bits are only accessed using such instructions, there's no danger of conflicts. 由于仅使用这些指令访问保存位的存储器位置,因此不存在冲突的危险。

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

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