我正在使用位域来轻松访问浮点库我试图为没有FPU的微控制器.
问题是我似乎无法使用bitfields.看一看:
typedef struct
{
union{
unsigned long mantissa: 23;
unsigned long exponent: 8;
unsigned long sign: 1;
float all;
};
}_float __attribute__((__packed__));
Run Code Online (Sandbox Code Playgroud)
问题是,当我尝试访问或更改任何内容时,它会将位域分别视为末尾的1,8,23位.虽然它应该是从末尾开始的23位,然后是8位然后是最后一位.除非我完全误解了bitfields的使用.我认为使用打包可以解决问题,但你可以看到它没有.
任何帮助将非常感激.我不止一次谷歌搜索这个网站,所以我寄予厚望.
而不是这样做为标志枚举变量添加一个值:
MyFlags flags = MyFlags.Pepsi;
flags = flags | MyFlags.Coke;
Run Code Online (Sandbox Code Playgroud)
我想创建一个扩展方法来实现这一点:
MyFlags flags = MyFlags.Pepsi;
flags.Add(MyFlags.Coke);
Run Code Online (Sandbox Code Playgroud)
可能?你怎么做呢?
如果使用位运算符(会发生什么事&,|等)来比较两个大小不同的位域?
例如,0 1 1 0与0 0 1 0 0 0 0 1:
0 1 1 0 0 0 0 0 The smaller one is extended with zeros and pushed to the
0 0 1 0 0 0 0 1 most-significant side.
Run Code Online (Sandbox Code Playgroud)
要么...
0 0 0 0 0 1 1 0 The smaller one is extended with zeros and pushed to the
0 0 1 0 0 0 0 1 least-significant side.
Run Code Online (Sandbox Code Playgroud)
要么... …
我从硬件接收了几个位字段.
我的代码最初是:
public readonly byte LowByte;
public bool Timer { get { return (LowByte & 1) == 1; } }
Run Code Online (Sandbox Code Playgroud)
然后我想起了标志枚举,我正在考虑将其更改为:
[Flags]
public enum LowByteReasonValues : byte
{
Timer = 1,
DistanceTravelledExceeded = 2,
Polled = 4,
GeofenceEvent = 8,
PanicSwitchActivated = 16,
ExternalInputEvent = 32,
JourneyStart = 64,
JourneyStop = 128
}
public readonly LowByteReasonValues LowByte;
public bool Timer { get { return (LowByte & LowByteReasonValues.Timer) == LowByteReasonValues.Timer; } }
Run Code Online (Sandbox Code Playgroud)
等等.
哪种方法最佳,哪种方法各有利弊?
编辑:我很想知道这两种方法之间是否存在任何实际差异,特别是在性能方面.我不希望征求关于编码风格的意见(除非它来自微软的指导方针),因为这会将问题视为非建设性的.谢谢.
问题说明了一切.
如果我有一个96位字段:
uint32_t flags[3]; //(thanks @jalf!)
Run Code Online (Sandbox Code Playgroud)
考虑到其中的子域可能位于32位边界(例如,从第29位到第35位的字段),我如何最好地访问它?
我需要访问尽可能快,所以我宁愿不将它们作为数组的32位元素进行迭代.
旧的方式,如果我们想要switch一些复杂的位掩码,我们可以很容易地这样做(从我头顶的一个随机例子来证明问题):
private static final int MAN = 0x00000001;
private static final int WOMAN = 0x00000002;
// ...alive, hungry, blind, etc.
private static final int DEAD = 0xFF000000;
public void doStuff(int human) {
switch (human) {
case MAN | DEAD:
// do something
break;
// more common cases
}
}
Run Code Online (Sandbox Code Playgroud)
如今,因为我们使用enums和EnumSets,我有时喜欢做类似的事情:
enum Human {
MAN, WOMAN, DEAD; // etc.
}
public void doStuff(EnumSet human) {
switch (human) {
case Human.MAN | Human.DEAD:
// do something …Run Code Online (Sandbox Code Playgroud) #include <stdint.h>
#include <stdio.h>
typedef union {
uint64_t u[2];
struct {
uint64_t a:30;
uint64_t b:30;
uint64_t c:30;
uint64_t d:30;
uint64_t e:8;
}x;
} mystruct;
int main()
{
printf("Size %d\n", sizeof(mystruct));
}
Run Code Online (Sandbox Code Playgroud)
我想在64位机器上编译它.预期的输出是16但我得到24.我知道这里发生了一些对齐,但我不确定为什么结构x正好是16个字节.有人可以解释一下吗.谢谢
我正在编写一个与VHDL中定义的许多寄存器接口的应用程序.寄存器为32位宽,并分配成组.我为该组的每个成员提供了组的基址和32位偏移量.以下是一个组的示例,组内的寄存器和寄存器的结构.


目前,使用以下位字段结构处理I/O,
typedef struct
{
uint32_t data0 : 12;
uint32_t data1 : 1;
...
}volatile data_port;
Run Code Online (Sandbox Code Playgroud)
并使用指向地址的指针修改字段,
data_port *const p_data = (data_port *)0xc006380;
Run Code Online (Sandbox Code Playgroud)
虽然这可能在这个平台上有效,但是对于当前的编译器,我担心可移植性.我想知道在强制使用这些非常规数据类型时是否有更好的方法来处理硬件接口?
我能想到的另一种选择是在硬件和寄存器结构之间创建另一层,使用易失性无符号int指针,并在应用层中使用位域结构.问题是,数据仍然必须从位字段(可能在另一个平台上以不同方式对齐)复制到int,这可能是另一个主题.
编辑:
我认为我真正想要的是一种消除位域使用的方法.将具有位字段成员的结构映射到硬件实际上似乎是一种糟糕的方法.所以,为了消除这一点,我将使用以下之一作为指向易失性存储器地址的指针,
#define PeripheralBase ((uint32_t volatile *)BASE)
Run Code Online (Sandbox Code Playgroud)
要么
uint32_t volatile *const peripheral_base = (uint32_t *) BASE;
Run Code Online (Sandbox Code Playgroud)
希望,一旦我达到这一点,一切都将在32位内完全一致.我想要做的一个方法是创建相同的data_port结构,但是删除位打包,然后右边一个函数专门为每个寄存器将位移位到unsigned int,然后可以使用它传递给寄存器易失性指针.
就像是,
static inline uint32_t struct_to_uint(data_port *data)
{
return data->data0
+ ((uint32_t)data->data1 << 12)
+ ((uint32_t)data->data2 << 13)
+ .....;
}
Run Code Online (Sandbox Code Playgroud)
我不确定语法是否正确,但我们的想法是将值转移而不必担心编译器或平台.这是否因为?这种方法是否存在可移植性问题?
我相信,直到C++ 14,声明为结构的结构域的某个字段int仍被解释为signed或者unsigned,解释是实现定义的.参考:http://en.cppreference.com/w/cpp/language/bit_field.
在C++ 14中仍然如此吗?即,下面的代码是否保证按照有意义工作?
#include <iostream>
struct X
{
int f:3;
};
int main()
{
X x;
x.f = -2; // is this going to be indeed signed? It seems so.
std::cout << x.f << std::endl; // displays -2
}
Run Code Online (Sandbox Code Playgroud) 在讨论位域时,C++ 17标准在第12.2.4节中多次使用术语"分配单元",但似乎没有定义该术语的含义.该标准还指出,"作为特殊情况,宽度为零的未命名位域指定分配单元边界处下一个位字段的对齐."
所以我对这些概念有两个问题,使用下面的代码作为例子:
该标准的术语"分配单位"是什么意思?
为未命名的位域指定的数据类型有何意义?
在第二个问题中,我的假设是数据类型意味着后面的位字段应该在该数据类型的下一个边界上对齐.
struct tag
{
char X:3;
unsigned int :0; // start next bit-field on next unsigned int boundary?
char Y:4;
unsigned char :0; // start next bit-field on next unsigned char boundary?
long Z:32;
};
Run Code Online (Sandbox Code Playgroud)