C99标准的第6.3.1.1节包含:
以下内容可用于任何地方
int或unsigned int可能使用的表达式:[...]类型的位字段
_Bool,int,signed int,或unsigned int.如果a
int可以表示原始类型的所有值,则该值将转换为int; 否则,它被转换为unsigned int.
在我看来,这意味着unsigned int位字段被提升为int,除非无符号位字段的宽度等于宽度int,在这种情况下最后一个短语适用.
我有以下程序:
struct S { unsigned f:32; } x = { 28349};
unsigned short us = 0xDC23L;
main(){
int r = (x.f ^ ((short)-87)) >= us;
printf("%d\n", r);
return r;
}
Run Code Online (Sandbox Code Playgroud)
还有两个系统来执行这个程序(int在两个系统上都是32位).一个系统说这个程序打印1,另一个系统说它打印0.我的问题是,我应该在哪两个系统中提交错误报告?(我倾向于针对打印0的系统提交报告,因为上面的摘录)
我想知道是否有一个GCC C编译器指令允许我确定结构打包的位顺序?喜欢的东西:
#pragma bit_order left
Run Code Online (Sandbox Code Playgroud)
这种需求的基本原理是我有以下结构:
struct {
union {
unsigned char BYTE;
struct {
unsigned char B0: 1;
unsigned char B1: 1;
unsigned char B2: 1;
unsigned char B3: 1;
unsigned char B4: 4;
}BIT;
}ITEM;
} myStruct;
Run Code Online (Sandbox Code Playgroud)
有了这个结构,我希望编译器以这种方式打包它:
Bit order: | 7 6 5 4 3 2 1 0 |
Label: |B0 B1 B2 B3 B4 B5 B6 B7 |
Run Code Online (Sandbox Code Playgroud)
而不是GCC如何做到:
Bit order: | 7 6 5 4 3 2 1 0 |
Label: |B7 B6 B5 B4 …Run Code Online (Sandbox Code Playgroud) 我正在为二进制格式编写解析器.这种二进制格式涉及不同的表,这些表再次是二进制格式,通常包含不同的字段大小(大约在50到100之间).
这些结构中的大多数将具有位域,并且在用C表示时将看起来像这些:
struct myHeader
{
unsigned char fieldA : 3
unsigned char fieldB : 2;
unsigned char fieldC : 3;
unsigned short fieldD : 14;
unsigned char fieldE : 4
}
Run Code Online (Sandbox Code Playgroud)
我遇到了struct模块,但意识到它的最低分辨率是一个字节而不是一点,否则该模块几乎适合这项工作.
我知道使用ctypes支持位域,但我不知道如何在这里连接包含位域的ctypes结构.
我的另一个选择是自己操作这些位并将其提供给字节并将其与struct模块一起使用 - 但由于我有接近50-100种不同类型的此类结构,因此编写代码变得更容易出错.我也担心效率,因为这个工具可能用于解析大千兆字节的二进制数据.
谢谢.
我正在搞乱一些相当低级别的东西,并试图确定为什么我使用CorFlags.exe实用程序得到不同的输出.作为参考,输出如下:
$ corflags test2.exe Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.30319.17929 Copyright (c) Microsoft Corporation. All rights reserved. Version : v4.0.30319 CLR Header: 2.5 PE : PE32 CorFlags : 0x1 ILONLY : 1 32BITREQ : 0 32BITPREF : 0 Signed : 0 $ corflags test.exe Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.30319.17929 Copyright (c) Microsoft Corporation. All rights reserved. Version : v4.0.30319 CLR Header: 2.5 PE : PE32 CorFlags : 0x20003 ILONLY : 1 32BITREQ : …
C/C++位域似乎在硬件驱动程序和二进制网络传输中有很多应用.但是它们似乎并没有被广泛使用,并且通常不鼓励,因为实际的二进制布局是特定于实现的,如C99标准6.7.2.1/10中的引用所示 - "结构和联合说明符";
实现可以分配足够大的任何可寻址存储单元来保持位域.如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中.如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的.单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的.未指定可寻址存储单元的对齐.
我的问题很简单; 为什么委员会决定将位字段保留为特定于实现的东西,从而使其成为编译器构造,主要用于减少内存使用,在许多情况下它可用于提供良好的二进制布局,并且免费开发人员从小巧的代码?
这是关于ANSI-C(C90).这就是我所知道的:
我熟悉语法.
我有关于位域的问题:
我正在尝试为SET创建一个结构,它必须对内存部分尽可能高效.
我试过了:
typedef struct set
{
unsigned int var: 1;
} SET;
//now define an array of SETS
SET array_of_sets[MAX_SIZE] //didn't define MAX_SIZE, but no more than 1024 elements in each set.
Run Code Online (Sandbox Code Playgroud)
我知道这不高效; 也许它对我想要的东西甚至不好.这就是为什么我在寻求帮助.
我有一个代码,它使用如下声明的位字段
typedef struct my{
const char *name;
uint8_t is_alpha : 1;
uint8_t is_hwaccel : 1;
uint8_t x_chroma_shift;
uint8_t y_chroma_shift;
} mystr;
Run Code Online (Sandbox Code Playgroud)
uint8_t是typedef'ed unsigned char.
使用此位字段在MS-VS 2008中构建代码会发出如下警告:
imgconvert.c(60) : warning C4214: nonstandard extension used : bit-field types other than int.
我有四个2位位域存储在一个字节中.因此,每个位域可以表示0,1,2或3.例如,以下是前3个位域为零的4个可能值:
00 00 00 00 = 0 0 0 0
00 00 00 01 = 0 0 0 1
00 00 00 10 = 0 0 0 2
00 00 00 11 = 0 0 0 3
Run Code Online (Sandbox Code Playgroud)
我想要一种有效的方法来对四个位域进行求和.例如:
11 10 01 00 = 3 + 2 + 1 + 0 = 6
Run Code Online (Sandbox Code Playgroud)
现代Intel x64 CPU上的8位查找表需要4个周期才能从L1返回答案.似乎应该有一些方法来比这更快地计算答案.3个周期为6-12个简单位操作提供了空间.作为首发,简单的面具和换挡在Sandy Bridge上需要5个周期:
假设位字段是:d c b a,并且该掩码是:00 00 00 11
从艾拉帮助澄清:这假设a,b,c,和d是相同的,都被设置为初始byte.奇怪的是,我想我可以免费做到这一点.因为我每循环可以做2次加载,而不是加载byte一次,我可以加载它四次:a …
当你写作
struct {
unsigned a:3, b:2;
} x = {10, 11};
Run Code Online (Sandbox Code Playgroud)
被x.b保证是3由ANSI C(C89)?我已阅读并重新阅读标准,但似乎无法找到确切的情况.
例如,"无法用结果无符号整数类型表示的结果以模数的形式减少,该数字大于可由结果无符号整数类型表示的最大值." 谈论计算,而不是初始化.而且,位字段实际上不是一种类型.
此外,(当谈到无符号t:4时)"包含[0,15]范围内的值",但这并不一定意味着初始化器必须以模16减少以映射到[0,15].
结构初始化真的是详细描述,但我似乎无法找到确切的行为.(当然编译器就是这样做的.而且IBM文档说"当你将一个超出范围的值分配给一个位字段时,保留低位模式并分配适当的位.",但是我想要要知道ANSI C是否标准化了.
编辑2:
当以前驻留在 C++ 源文件中但逐字移入 C 文件的函数开始返回不正确的结果时,我正在调试一个奇怪的测试失败。下面的 MVE 允许重现 GCC 的问题。然而,当我一时兴起用 Clang(后来用 VS)编译这个例子时,我得到了不同的结果!我不知道是将其视为其中一个编译器中的错误,还是将其视为 C 或 C++ 标准允许的未定义结果的表现。奇怪的是,没有一个编译器给我任何关于表达式的警告。
罪魁祸首是这个表达式:
ctl.b.p52 << 12;
Run Code Online (Sandbox Code Playgroud)
在这里,p52输入为uint64_t; 它也是工会的一部分(见control_t下文)。移位操作不会丢失任何数据,因为结果仍然适合 64 位。但是,如果我使用 C 编译器,那么 GCC 决定将结果截断为 52 位!使用 C++ 编译器,所有 64 位结果都被保留。
为了说明这一点,下面的示例程序编译了两个具有相同主体的函数,然后比较它们的结果。c_behavior()放在 C 源文件和cpp_behavior()C++ 文件中,并main()进行比较。
带有示例代码的存储库:https : //github.com/grigory-rechistov/c-cpp-bitfields
头文件 common.h 定义了 64 位宽位域和整数的联合,并声明了两个函数:
#ifndef COMMON_H
#define COMMON_H
#include <stdint.h>
typedef union control {
uint64_t q;
struct {
uint64_t a: 1;
uint64_t …Run Code Online (Sandbox Code Playgroud) bit-fields ×10
c ×8
c++ ×2
struct ×2
.net ×1
ansi ×1
assembly ×1
binary-data ×1
c99 ×1
corflags ×1
ctypes ×1
gcc ×1
low-level ×1
optimization ×1
python ×1
standards ×1
truncation ×1
visual-c++ ×1