C语言 什么时候在 C 中使用位域?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24933242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When to use bit-fields in C?
提问by YohanRoth
On the question 'why do we need to use bit-fields', searching on Google I found that bit fields are used for flags. Now I am curious, is it the only way bit-fields are used practically? Do we need to use bit fields to save space?
关于“为什么我们需要使用位字段”的问题,在 Google 上搜索我发现位字段用于标志。现在我很好奇,这是实际使用位域的唯一方法吗?我们是否需要使用位域来节省空间?
Way of defining bit field from the book:
书中定义位域的方法:
struct {
unsigned int is_keyword : 1;
unsigned int is_extern : 1;
unsigned int is_static : 1;
} flags;
Why do we use int? How much space is occupied? I am confused why we are using int, but not short or something smaller than an int. As I understand only 1 bit is occupied in memory, but not the whole unsigned int value. Is it correct?
为什么我们使用int?占用了多少空间?我很困惑为什么我们使用 int,而不是 short 或比 int 小的东西。据我所知,内存中只占用了 1 位,而不是整个 unsigned int 值。这是正确的吗?
采纳答案by Eric Finn
Now I am curious, [are flags] the only way bit-fields are used practically?
现在我很好奇,[是标志] 位域实际使用的唯一方式吗?
No, flags are not the the only way bit-fields are used. They can also be used to store values larger than one bit, although flags are more common. For instance:
不,标志不是使用位域的唯一方式。它们也可用于存储大于一位的值,尽管标志更为常见。例如:
typedef enum {
NORTH = 0,
EAST = 1,
SOUTH = 2,
WEST = 3
} directionValues;
struct {
unsigned int alice_dir : 2;
unsigned int bob_dir : 2;
} directions;
Do we need to use bit fields to save space?
我们是否需要使用位域来节省空间?
Bit fields do save space. They also allow an easier way to set values that aren't byte-aligned. Rather than bit-shifting and using bitwise operations, we can use the same syntax as setting fields in a struct. This improves readability. With a bitfield, you could write
位字段确实节省了空间。它们还允许一种更简单的方法来设置非字节对齐的值。我们可以使用与在struct. 这提高了可读性。使用位域,你可以写
directions.bob_dir = SOUTH;
However, doing it manually, you would need to write something like:
但是,手动执行此操作,您需要编写如下内容:
#define BOB_OFFSET 2
directions &= ~(3<<BOB_OFFSET); // clear Bob's bits
directions |= SOUTH<<BOB_OFFSET;
This improved readability is arguably more important than saving a few bytes here and there.
这种提高的可读性可以说比在这里和那里保存几个字节更重要。
Why do we use int? How much space is occupied?
为什么我们使用int?占用了多少空间?
The space of an entire intis occupied. We use intbecause in many cases, it doesn't really matter. If, for a single value, you use 4 bytes instead of 1 or 2, your user probably won't notice. For some platforms, size does matter more, and you can use other data types which take up less space (char, short, uint8_t, etc).
整个空间int都被占用了。我们使用int是因为在很多情况下,这并不重要。如果对于单个值,您使用 4 个字节而不是 1 个或 2 个,您的用户可能不会注意到。对于某些平台,尺寸的确很重要多了,你可以使用占用空间少(其它数据类型char,short,uint8_t,等)。
As I understand only 1 bit is occupied in memory, but not the whole unsigned int value. Is it correct?
据我所知,内存中只占用了 1 位,而不是整个 unsigned int 值。这是正确的吗?
No, that is not correct. The entire unsigned intwill exist, even if you're only using 8 of its bits.
不,那是不正确的。整个unsigned int将存在,即使您只使用其 8 位。
回答by rioki
A quite good resource is Bit Fields in C.
一个很好的资源是C 中的位字段。
The basic reason is to reduce the size used. For example if your write:
根本原因是减少使用的大小。例如,如果你写:
struct {
unsigned int is_keyword;
unsigned int is_extern;
unsigned int is_static;
} flags;
You will use at least 3 * sizeof(unsigned int)or 12 bytes to represent 3 little flags, that should only need 3 bits.
您将使用至少3 * sizeof(unsigned int)12 个字节来表示 3 个小标志,这应该只需要 3 位。
So if you write:
所以如果你写:
struct {
unsigned int is_keyword : 1;
unsigned int is_extern : 1;
unsigned int is_static : 1;
} flags;
This uses up the same space as one unsigned int, so 4 bytes. You can throw 32 one bit fields into the struct before it needs more space.
这使用了与 one 相同的空间unsigned int,所以是 4 个字节。在需要更多空间之前,您可以将 32 个一位字段放入结构中。
This is sort of equivalent to the classical home brew bit field:
这有点相当于经典的自制位字段:
#define IS_KEYWORD 0x01
#define IS_EXTERN 0x02
#define IS_STATIC 0x04
unsigned int flags;
But the bit field syntax is cleaner, compare:
但是位域语法更清晰,比较:
if (flags.is_keyword)
against:
反对:
if (flags & IS_KEYWORD)
and obviously less error prone.
并且显然更不容易出错。
回答by undur_gongor
Another place where bitfields are common are hardware registers. If you have a 32 bit register where each bit has a certain meaning, you can elegantly describe it with a bitfield.
位域常见的另一个地方是硬件寄存器。如果您有一个 32 位寄存器,其中每个位都有一定的含义,您可以用位域来优雅地描述它。
Such a bitfield is inherently platform-specific. Portability does not matter in this case.
这样的位域本质上是特定于平台的。在这种情况下,可移植性无关紧要。
回答by Theodoros Chatzigiannakis
We use bit fields mostly (though not exclusively) for flag structures - bytes or words (or possibly larger things) in which we try to pack tiny (often 2-state) pieces of (often related) information.
我们主要(尽管不是唯一地)将位域用于标志结构 - 字节或字(或可能更大的事物),我们试图在其中打包微小(通常是 2 状态)(通常是相关的)信息。
In these scenarios, bit fields are used because they correctly model the problem we're solving: what we're dealing with is not really an 8-bit (or 16-bit or 24-bit or 32-bit) number, but rather a collection of 8 (or 16 or 24 or 32) related, but distinct pieces of information.
在这些场景中,使用位字段是因为它们正确地模拟了我们正在解决的问题:我们正在处理的实际上并不是一个 8 位(或 16 位或 24 位或 32 位)数字,而是8 条(或 16 条、24 条或 32 条)相关但不同的信息的集合。
The problems we solve using bit fields are problems where "packing" the information tightly has measurable benefits and/or "unpacking" the information doesn't have a penalty. For example, if you're exposing 1 byte through 8 pins and the bits from each pin go through their own bus that's already printed on the board so that it leads exactly where it's supposed to, then a bit field is ideal. The benefit in "packing" the data is that it can be sent in one go (which is useful if the frequency of the bus is limited and our operation relies on frequency of its execution), and the penalty of "unpacking" the data is non-existent (or existent but worth it).
我们使用位域解决的问题是“打包”信息具有可衡量的好处和/或“解包”信息没有惩罚的问题。例如,如果您通过 8 个引脚暴露 1 个字节,并且每个引脚的位通过已经印在板上的自己的总线,以便它准确地引导到它应该到达的位置,那么位域是理想的。“打包”数据的好处是可以一次性发送(如果总线的频率有限并且我们的操作依赖于它的执行频率,这很有用),而“解包”数据的惩罚是不存在(或存在但值得)。
On the other hand, we don't use bit fields for booleans in other cases like normal program flow control, because of the way computer architectures usually work. Most common CPUs don't like fetching one bit from memory - they like to fetch bytes or integers. They also don't like to process bits - their instructions often operate on larger things like integers, words, memory addresses, etc.
另一方面,由于计算机体系结构通常的工作方式,我们在其他情况下(如正常程序流控制)不使用布尔值的位字段。大多数常见的 CPU 不喜欢从内存中获取一位——他们喜欢获取字节或整数。他们也不喜欢处理位——他们的指令通常对更大的东西进行操作,比如整数、字、内存地址等。
So, when you try to operate on bits, it's up to you or the compiler (depending on what language you're writing in) to write out additional operations that perform bit masking and strip the structure of everything but the information you actually want to operate on. If there are no benefits in "packing" the information (and in most cases, there aren't), then using bit fields for booleans would only introduce overhead and noise in your code.
因此,当您尝试对位进行操作时,取决于您或编译器(取决于您使用的语言)编写执行位掩码的附加操作并剥离除您实际想要的信息之外的所有内容的结构操作。如果“打包”信息没有任何好处(在大多数情况下,没有好处),那么将位字段用于布尔值只会在您的代码中引入开销和噪音。
回答by Jeegar Patel
why do we need to use bit-fields'?
为什么我们需要使用位域'?
When you want to store some data whose can be stored less than byte those kind of data can be coupled in structure using Bit fields. In embedded word, When one 32 bit world of any register has different meaning for different word then also you can use bit fileds to make them more readable.
当您想存储一些可以存储小于字节的数据时,可以使用位字段在结构中耦合这些数据。在嵌入字中,当任何寄存器的一个 32 位世界对不同的字具有不同的含义时,您也可以使用位文件来使它们更具可读性。
I found that bit fields are used for flags. Now I am curious, is it the only way bit-fields are used practically?
我发现位字段用于标志。现在我很好奇,这是实际使用位域的唯一方法吗?
No this not the only way. You can use it in other way also.
不,这不是唯一的方法。您也可以以其他方式使用它。
Do we need to use bit fields to save space?
我们是否需要使用位域来节省空间?
Yes.
是的。
As I understand only 1 bit is occupied in memory, but not the whole unsigned int value. Is it correct?
据我所知,内存中只占用了 1 位,而不是整个 unsigned int 值。这是正确的吗?
NO. Memory only can be occupied in multiple of byte only.
不。内存只能以字节的倍数占用。
回答by LeSpocky
To answer the original question ?When to use bit-fields in C?? … according to the book "Write Portable Code" by Brian Hook (ISBN 1-59327-056-9, I read the German edition ISBN 3-937514-19-8) and to personal experience:
回答最初的问题?什么时候在 C 中使用位域??...根据 Brian Hook 所著的“编写便携式代码”一书(ISBN 1-59327-056-9,我阅读了德语版 ISBN 3-937514-19-8)和个人经验:
NEVER use the bitfield idiom of the C language but do it by yourself.
永远不要使用 C 语言的位域习语,而要自己动手。
A lot of implementation details are compiler specific, especially in combination with unions and things are not guaranteed over different compilers and different endianess. If there's only a tiny chance your code has to be portable and will be compiled for different architectures and/or with different compilers, don't use it.
许多实现细节是特定于编译器的,尤其是与联合相结合的情况下,不同的编译器和不同的字节序不能保证事情的发展。如果您的代码必须是可移植的并且将针对不同的体系结构和/或使用不同的编译器进行编译,那么请不要使用它。
We had this case when porting code from little endian micro controller with some proprietary compiler to another big endian micro controller with GCC and it was not fun. :-/
我们在将代码从带有一些专有编译器的小端微控制器移植到另一个带有 GCC 的大端微控制器时遇到了这种情况,这并不有趣。:-/
This is how I use flags (host byte order ;-) ) since then:
这就是我从那时起使用标志(主机字节顺序 ;-) )的方式:
# define SOME_FLAG (1 << 0)
# define SOME_OTHER_FLAG (1 << 1)
# define AND_ANOTHER_FLAG (1 << 2)
/* test flag */
if ( someint & SOME_FLAG ) {
/* do this */
}
/* set flag */
someint |= SOME_FLAG;
/* clear flag */
someint &= ~SOME_FLAG;
No need for a union with the int type and some bitfield struct then. If you read lots of embedded code those test, set, and clear patterns will become common and you spot them easily in your code.
不需要与 int 类型和一些位域结构的联合。如果您阅读大量嵌入式代码,那么这些测试、设置和清晰的模式将变得很普遍,并且您很容易在代码中发现它们。
回答by Luis Masuelli
A good usage would be to implement a chunk to translate to-and from-base64 or any unaligned data structure.
一个很好的用法是实现一个块来转换到和从 base64 或任何未对齐的数据结构。
struct {
unsigned int e1:6;
unsigned int e2:6;
unsigned int e3:6;
unsigned int e4:6;
} base64enc; //I don't know if declaring a 4-byte array will have the same effect.
struct {
unsigned char d1;
unsigned char d2;
unsigned char d3;
} base64dec;
union base64chunk {
struct base64enc enc;
struct base64dec dec;
};
base64chunk b64c;
//you can assign 3 characters to b64c.enc, and get 4 0-63 codes from b64dec instantly.
This example is a bit naive, since base64 must also consider null-termination (i.e. a string which has not a length lso that l% 3 is 0). But works as a sample of accessing unaligned data structures.
这个例子有点幼稚,因为 base64 还必须考虑空终止(即一个没有长度的字符串,l因此l%3 为 0)。但作为访问未对齐数据结构的示例。
Another example: Using this feature to break a TCP packet header into its components(or other network protocol packet header you want to discuss), althought it is a more advanced and less end-user example. In general: this is useful regarding PC internals, SO, drivers, an encoding systems.
另一个示例:使用此功能将TCP 数据包标头分解为其组件(或您要讨论的其他网络协议数据包标头),尽管它是一个更高级且最终用户较少的示例。一般来说:这对于 PC 内部、SO、驱动程序、编码系统很有用。
Another example: analyzing a floatnumber.
另一个例子:分析一个float数字。
struct _FP32 {
unsigned int sign:1;
unsigned int exponent:8;
unsigned int mantissa:23;
}
union FP32_t {
_FP32 parts;
float number;
}
(Disclaimer: Don't know the file name / type name where this is applied, but in C this is declared in a header; Don't know how can this be done for 64-bit flaots since the mantissa must have 52bits and -in a 32bit target- ints have 32 bits).
(免责声明:不知道应用它的文件名/类型名称,但在 C 中,这是在头文件中声明的;不知道如何为 64 位浮标完成此操作,因为尾数必须有 52 位和 -在 32 位目标中,整数有 32 位)。
Conclusion:As the concept and these examples show, this is a rarely used feature because it's mostly for internal purposes, and not for day-by-day software.
结论:正如概念和这些示例所示,这是一个很少使用的功能,因为它主要用于内部目的,而不是用于日常软件。
回答by rohit
Bit fields can be used for saving memory space (but using bit field for this purpose is rare). It is used where there is memory constraint. eg) while programming in embedded systems.
位域可用于节省内存空间(但为此目的使用位域的情况很少见)。它用于存在内存限制的地方。例如)在嵌入式系统中编程时。
But this should be used only if extremely required.
但是只有在非常需要时才应该使用它。
Because we cannot have the address of a bit field. So address operator &cannot be used with them.
因为我们不能有位域的地址。所以地址运算符&不能与它们一起使用。
回答by this
You can use them to expand the number of unsigned types that wrap. Ordinary you would have only powers of 8,16,32,64... , but you can have every power with bit-fields.
您可以使用它们来扩展包装的无符号类型的数量。通常,您只有 8,16,32,64... 的幂,但您可以拥有位域的所有幂。
struct a
{
unsigned int b : 3 ;
} ;
struct a w = { 0 } ;
while( 1 )
{
printf("%u\n" , w.b++ ) ;
getchar() ;
}
回答by Tim B
To answer the parts of the question no-one else answered:
要回答没有其他人回答的问题的部分:
Ints not Shorts
整数不是短裤
The reason to use ints rather than shorts etc is that in most cases no space will be saved by doing so.
使用 int 而不是 short 等的原因是,在大多数情况下,这样做不会节省空间。
Modern computers have a 32 or 64 bit architecture and that 32 or 64 bits will be needed even if you use a smaller storage type such as a short.
现代计算机具有 32 或 64 位体系结构,即使您使用更小的存储类型(例如 short),也需要 32 或 64 位。
The smaller types are only useful for saving memory if you can pack them together (for example a short array may use less memory than an int array as the shorts can be packed together tighter in the array). For most cases when using bitfields this is not the case.
较小的类型仅在您可以将它们打包在一起时才用于节省内存(例如,短数组可能比 int 数组使用更少的内存,因为数组中的 short 可以更紧密地打包在一起)。对于使用位域的大多数情况,情况并非如此。
Other uses
其他用途
Bitfields are most commonly used for flags, but there are other things they are used for. For example one way to represent a chess board used in a lot of chess algorithms is to use a 64 bit integer to represent the board (8*8 pixels) and set flags in that integer to give the position of all the white pawns. Another integer shows all the black pawns, etc.
位域最常用于标志,但它们还有其他用途。例如,在许多国际象棋算法中表示棋盘的一种方法是使用 64 位整数来表示棋盘(8*8 像素)并在该整数中设置标志以给出所有白色棋子的位置。另一个整数显示所有黑色棋子等。

