我早就知道C中有位字段,偶尔我会用它们来定义密集的结构:
typedef struct Message_s {
unsigned int flag : 1;
unsigned int channel : 4;
unsigned int signal : 11;
} Message;
Run Code Online (Sandbox Code Playgroud)
当我阅读开源代码时,我经常会发现位掩码和位移操作,以便在手工滚动的位域中存储和检索这些信息.这是如此常见,我不认为作者不知道位字段语法,所以我想知道是否有理由通过位掩码滚动位字段并转移自己的操作而不是依赖编译器生成用于获取和设置此类位字段的代码.
我在这里读到位字段不可移植.这是否意味着下面定义位字段的代码(从这里获取的代码)无法在某些机器上编译?
如果是这样,为什么呢?
#include <stdio.h>
#include <string.h>
/* define simple structure */
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/* define a structure with bit fields */
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main( )
{
printf( "Memory size occupied by status1 : %d\n", sizeof(status1));
printf( "Memory size occupied by status2 : %d\n", sizeof(status2));
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我有这个C结构:(代表一个IP数据报)
struct ip_dgram
{
unsigned int ver : 4;
unsigned int hlen : 4;
unsigned int stype : 8;
unsigned int tlen : 16;
unsigned int fid : 16;
unsigned int flags : 3;
unsigned int foff : 13;
unsigned int ttl : 8;
unsigned int pcol : 8;
unsigned int chksm : 16;
unsigned int src : 32;
unsigned int des : 32;
unsigned char opt[40];
};
Run Code Online (Sandbox Code Playgroud)
我正在为它赋值,然后以16位字打印它的内存布局,如下所示:
//prints 16 bits at a time
void print_dgram(struct ip_dgram dgram)
{ …Run Code Online (Sandbox Code Playgroud) 我有一个由微控制器制造商提供的寄存器定义,可以作为位字段处理.寄存器定义如下:
#define SCU_WDTSCON0 (*( SCU_WDTSCON0_type *) 0xf00360f0u)
Run Code Online (Sandbox Code Playgroud)
位字段定义如下所示:
typedef volatile union {
unsigned U;
int I;
struct {
unsigned ENDINIT :1; // [0:0] End-of-Initialization Control Bit
unsigned LCK :1; // [1:1] Lock Bit to Control Access to WDTxCON0
unsigned HPW0 :2; // [3:2] Hardware Password 0
unsigned HPW1 :4; // [7:4] Hardware Password 1
unsigned PW :8; // [15:8] User-Definable Password Field for Access to WDTxCON0
unsigned REL :16; // [31:16] Reload Value for the WDT
} B;
} SCU_WDTSCON0_type; …Run Code Online (Sandbox Code Playgroud) 只是想知道关于 C 中 I²C 寄存器映射的最佳实践是什么,或者其他人经常/更喜欢使用什么。
到目前为止,我通常做了很多定义,一个用于每个寄存器,一个用于所有位、掩码、移位等。然而,最近我看到一些驱动程序使用(可能是打包的)结构而不是定义。我认为这些是 Linux 内核模块。
反正他们会
struct i2c_sensor_fuu_registers {
uint8_t id;
uint16_t big_register;
uint8_t another_register;
...
} __attribute__((packed));
Run Code Online (Sandbox Code Playgroud)
然后他们会使用 offsetof(或宏)来获取 i2c 寄存器并使用 sizeof 来读取要读取的字节数。
我发现这两种方法都有其优点:
结构方法:
定义方法:
基本上,我正在寻找一种更智能的方法来处理这些情况。我经常发现自己为每个寄存器和每个位键入了大量令人痛苦的长符号名称,还可能还有掩码和移位(后两个取决于数据类型),结果只使用其中的几个(但讨厌稍后重新定义丢失的符号,这就是我在一个会话中输入所有内容的原因)。不过,我注意到要读/写的字节大小大多是幻数,通常需要并排阅读数据表和源代码才能理解最基本的交互。
我想知道其他人如何处理这些情况?我在网上找到了一些例子,其中人们还在大标题中费力地输入每个寄存器、位等,但没有什么是确定的......但是,在这一点上,上述两个选项似乎都不太聪明:(
我正在寻找最优雅的接口上的输入来放置内存映射的寄存器接口,其中目标对象在寄存器中被分割:
union __attribute__ ((__packed__)) epsr_t {
uint32_t storage;
struct {
unsigned reserved0 : 10;
unsigned ICI_IT_2to7 : 6; // TOP HALF
unsigned reserved1 : 8;
unsigned T : 1;
unsigned ICI_IT_0to1 : 2; // BOTTOM HALF
unsigned reserved2 : 5;
} bits;
};
Run Code Online (Sandbox Code Playgroud)
在这种情况下,访问单个位T或任何reserved字段工作正常,但要读取或写入ICI_IT需求代码更像:
union epsr_t epsr;
// Reading:
uint8_t ici_it = (epsr.bits.ICI_IT_2to7 << 2) | epsr.bits.ICI_IT_0to1;
// Writing:
epsr.bits.ICI_IT_2to7 = ici_it >> 2;
epsr.bits.ICI_IT_0to1 = ici_it & 0x3;
Run Code Online (Sandbox Code Playgroud)
在这一点上,我已经失去了bitfield抽象试图提供的简单/便利的一大块.我考虑过宏观解决方案:
#define GET_ICI_IT(_e) ((_e.bits.ICI_IT_2to7 << …Run Code Online (Sandbox Code Playgroud) 我是一个来自C/C++的Rust初学者.首先,我尝试使用user32.MessageBox为Microsoft Windows创建一个简单的"Hello-World"程序,我偶然发现了与bitfields相关的问题.免责声明:所有代码段都是在SO编辑器中编写的,可能包含错误.
调用该函数的UTF-16LE版本所需的合并C声明是:
enum MessageBoxResult {
IDFAILED,
IDOK,
IDCANCEL,
IDABORT,
IDRETRY,
IDIGNORE,
IDYES,
IDNO,
IDTRYAGAIN = 10,
IDCONTINUE
};
enum MessageBoxType {
// Normal enumeration values.
MB_OK,
MB_OKCANCEL,
MB_ABORTRETRYIGNORE,
MB_YESNOCANCEL,
MB_YESNO,
MB_RETRYCANCEL,
MB_CANCELTRYCONTINUE,
MB_ICONERROR = 0x10UL,
MB_ICONQUESTION = 0x20UL,
MB_ICONEXCLAMATION = 0x30UL,
MB_ICONINFORMATION = 0x40UL,
MB_DEFBUTTON1 = 0x000UL,
MB_DEFBUTTON2 = 0x100UL,
MB_DEFBUTTON3 = 0x200UL,
MB_DEFBUTTON4 = 0x300UL,
MB_APPLMODAL = 0x0000UL,
MB_SYSTEMMODAL = 0x1000UL,
MB_TASKMODAL = 0x2000UL,
// Flag values.
MB_HELP = 1UL << 14,
MB_SETFOREGROUND = …Run Code Online (Sandbox Code Playgroud) 我正在实施无线电标准,并在结构和内存大小方面遇到了问题.在下面的例子中,我需要这个结构位于单个字节的内存中(按照无线电标准),但它目前给我2个字节的大小.经过多次挖掘后,我明白这是因为联盟的"大小"是字节而不是3位......但是还没有解决这个问题.我看过:
但似乎都没有给我一个解决方案.
有任何想法吗?
谢谢!
#ifdef WIN32
#pragma pack(push)
#pragma pack(1)
#endif
typedef struct three_bit_struct
{
unsigned char bit_a : 1;
unsigned char bit_b : 1;
unsigned char bit_c : 1;
}three_bit_struct_T;
typedef union
{
three_bit_struct_T three_bit_struct;
unsigned char another_three_bits : 3;
}weird_union_T;
typedef struct
{
weird_union_T problem_union;
unsigned char another_bit : 1;
unsigned char reserved : 4;
}my_structure_T;
int _tmain(int argc, _TCHAR* argv[])
{
int size;
size = sizeof(my_structure_T);
return 0;
}
#ifdef WIN32
#pragma pack(pop) …Run Code Online (Sandbox Code Playgroud) 我想知道内核编译器将如何处理不同的字节序位域:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8
ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8
version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
......
};
Run Code Online (Sandbox Code Playgroud) I wanted to implement LFSR(linear feedback shift registers) in C to generate random bits. When I try to modify an individual bit or just assign a short value to memory block, all the bits set to 1. How can I stop this from happening?
struct lfsr{
//...
union{
unsigned short ff_0 : 1;
unsigned short ff_1 : 1;
//...
unsigned short ff_f : 1;
unsigned short ff;
}flip_flops;
};
int main() {
struct lfsr gen;
gen.flip_flops.ff = 1; //all the …Run Code Online (Sandbox Code Playgroud) c ×9
bit-fields ×8
struct ×4
unions ×3
embedded ×2
bitflags ×1
c++ ×1
c99 ×1
i2c ×1
ip ×1
linux-kernel ×1
pointers ×1
portability ×1
principles ×1
rust ×1
unix ×1
winapi ×1