这仅适用于C++ 11:
如果我有一个常规的枚举如下:
enum TestType
{
Test0 = 0,
Test1,
Test2,
Test3,
Test4,
Test5,
Test6,
Test7
}
Run Code Online (Sandbox Code Playgroud)
和这样的压缩结构:
struct
{
TestType a : 3
uint32_t b : 5
} TestStruct;
Run Code Online (Sandbox Code Playgroud)
为TestStruct.a保证访问时等于任何有效的分配枚举值?或者编译器是否有可能分配已签名的基础类型,然后将位域a视为范围-4到3.
OpenCL语言不支持位域.不支持他们的原因是什么?与其他忽略的部分(递归,函数指针,......)不同,有明显的理由不支持它们,我没有看到一个用于位域.我确信这不是代表委员会的疏忽,但是原因是什么?
(我存储了一些打包在int中的位,并且代码可以更好地与它们一起读取.我理解bitfields是一种很好的语法,可以避免位移和来回屏蔽,无论如何它们都是在汇编中转换的.)
我试图在C++中使用位字段来实现特定的类大小,但由于某种原因它比我预期的要大.
问题是,一个32位(4字节)的类报告(当作为参数传递时sizeof)5个字节.下面的示例类:
typedef unsigned char u8;
typedef unsigned int u32;
class Test {
u8 four_bit_field : 4;
u8 eight_bit_field;
u32 twenty_bit_field : 20;
}__attribute__((packed));
Run Code Online (Sandbox Code Playgroud)
如果切换four_bit_field和eight_bit_field位置,则sizeof返回适当的大小,4个字节.我相信它可能是一个内存排列问题.
那么,有人知道这种行为背后的原因吗?而且,最重要的是,如何在不切换任何位置的情况下解决这个问题.
我正在尝试创建一个可变大小的颜色类 - 给定模板确定的值数组,我想为数组中的每个值创建命名别名,即:
template<int C = 3, typename T = unsigned char>
class Color {
public:
union {
T v[C];
struct {
T r, g, b, a;
};
};
};
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试为C = 3使用相同的类,则union要求4字节的大小('a'成员).或者,使用数学表达的位域大小((名为a,anonymous T成员的结构,大小在C> 3时评估为1),编译器发出一个允许警告(不可抑制,根据In gcc,如何静音 -敏感警告?),不适合大规模API的东西.
我如何允许单个类处理不同数量的变量,同时保留每个变量名称而不实现递归包含宏魔法(试过这个,不应该).提前致谢!
编辑:为了澄清问题,以下任何一个答案将解决此问题:
所以我最近遇到了这样的事情
unsigned char ch : 7;
Run Code Online (Sandbox Code Playgroud)
在一个结构内。我读了一点。显然这些被称为位域。它们用于设置字符可以接收的数据宽度。但是我们如何使用这些东西。例如,我知道我们可以将变量 ch 设置为一个字节
unsigned char ch = 0x61;
cout << ch << endl;
Run Code Online (Sandbox Code Playgroud)
这将输出
a
Run Code Online (Sandbox Code Playgroud)
但是,我们如何处理位域?
unsigned char ch : 7;
ch = 0x61; //This doesn't work for some reason
unsigned char ch : 7;
unsigned char ch = 0x61/ //Neither does this.
Run Code Online (Sandbox Code Playgroud)
谢谢您的帮助
虽然我有一个很好的LSFR C实现,我想我会在Haskell中尝试相同 - 只是为了看看它是怎么回事.到目前为止,我想出的是比C实现慢两个数量级,这引出了一个问题:性能如何得到改善?显而易见,这个小小的操作是瓶颈,而分析器确认了这一点.
这是使用列表的基线Haskell代码,并且Data.Bits:
import Control.Monad (when)
import Data.Bits (Bits, shift, testBit, xor, (.&.), (.|.))
import System.Environment (getArgs)
import System.Exit (exitFailure, exitSuccess)
tap :: [[Int]]
tap = [
[], [], [], [3, 2],
[4, 3], [5, 3], [6, 5], [7, 6],
[8, 6, 5, 4], [9, 5], [10, 7], [11, 9],
[12, 6, 4, 1], [13, 4, 3, 1], [14, 5, 3, 1], [15, 14],
[16,15,13,4], [17, 14], [18, 11], [19, 6, 2, 1],
[20, …Run Code Online (Sandbox Code Playgroud) 我必须定义一个通信协议,并且我想使用位字段来存储一些逻辑值。
我正在研究两个系统:发送方:设备和.Net 软件作为接收方。
在固件方面,我通常定义为位字段结构,例如:
struct __attribute__((__packed__)) BitsField
{
// Logic values
uint8_t vesselPresenceSw: 1;
uint8_t drawerPresenceSw: 1;
uint8_t pumpState: 1;
uint8_t waterValveState: 1;
uint8_t steamValveState: 1;
uint8_t motorDriverState: 1;
// Unused
uint8_t unused_0: 1;
uint8_t unused_1: 1;
};
Run Code Online (Sandbox Code Playgroud)
如何在软件方面定义相同的结构来支持字节反序列化来构建结构本身?
下面的getValue()成员函数是否违反了c ++严格别名规则?
根据标准,我认为setValue()违反了严格的别名规则,因为double既不是聚合类型也不是IEEE754_64的基类.
getValue()怎么样?当数据成员是位字段形式时,它是一个未定义的行为,如下例所示?
我在一个大型项目中使用类似的代码.GCC -O2和-O3输出错误的值.如果我添加-fno-strict-aliasing,问题就消失了.此外,如果我使用memcpy而不是在getValue()中进行转换,问题就消失了.不确定它是否是GCC错误.
#include <iostream>
#include <cstring>
using namespace std;
struct IEEE754_64
{
void setValue(double);
unsigned long long getValue();
// Data members
unsigned long long d_mantissa : 52;
long long d_exponent : 11;
unsigned long long d_sign : 1;
};
void IEEE754_64::setValue(double d)
{
(*this) = *reinterpret_cast<IEEE754_64*>(&d);
}
unsigned long long IEEE754_64::getValue()
{
return * reinterpret_cast<unsigned long long *>(this);
}
int main()
{
double b = 1.0;
IEEE754_64 d;
memcpy(&d, &b, sizeof(double));
cout<<hex<<d.getValue()<<endl;
d.setValue(1.0);
cout<<hex<<d.getValue()<<endl;
return 0; …Run Code Online (Sandbox Code Playgroud) int使用 Clang 和unsigned intGCC为 x86_64 编译时会打印以下代码。
我不确定哪个(如果有的话)是正确的。
#include <stdio.h>
struct s {
unsigned int x : 1;
};
template<typename T>
void f(T) {}
template<> void f<int>(int) {
printf("int\n");
}
template<> void f<unsigned int>(unsigned int) {
printf("unsigned int\n");
}
struct s r;
int main()
{
f(0 ? r.x : 0);
}
Run Code Online (Sandbox Code Playgroud)
如果我们用(r.x + 0)两个编译器替换条件,就说类型是有符号的。
C++ 标准部分 expr.cond 有许多转换规则,但似乎没有一个案例涵盖不同类型的泛左值和纯右值之间的转换问题。
是否将无符号位域提升为有符号整数是否由实现定义?
具有位域的结构,即使在“打包”时,似乎也会根据指定的 int 类型来处理位域的大小(以及对齐方式?)。有人可以指出定义该行为的 C++ 规则吗?我尝试了十几个编译器和体系结构(谢谢你,编译器资源管理器!),结果在所有编译器和体系结构中都是一致的。
这是要使用的代码: https: //godbolt.org/z/31zMcnboY
#include <cstdint>
#pragma pack(push, 1)
struct S1{ uint8_t v: 1; }; // sizeof == 1
struct S2{ uint16_t v: 1; }; // sizeof == 2
struct S3{ uint32_t v: 1; }; // sizeof == 4
struct S4{ unsigned v: 1; }; // sizeof == 4
#pragma pack(pop)
auto f(auto s){ return sizeof(s); }
int main(){
f(S1{});
f(S2{});
f(S3{});
f(S4{});
}
Run Code Online (Sandbox Code Playgroud)
生成的 ASM 清楚地显示了、
的返回大小分别f()为 1、2、4 :S1S2 …
c++ bit-packing language-lawyer bit-fields structure-packing