我已经学会了但并没有真正得到工会.我经历的每一个C或C++文本都会介绍它们(有时会传递),但是它们往往只提供很少的实际例子来说明为什么或在哪里使用它们.工会什么时候可以用于现代(甚至遗留)案件?我只有两个猜测是编程微处理器,当你的空间非常有限,或者你正在开发一个API(或类似的东西),并且你想迫使最终用户只有一个对象/类型的实例一度.这两个猜测是否接近正确?
目的
我正在用C语言编写一个网络程序(特别是gnu89),我希望通过重新解释一个特定的struct X大字节数组(也就是说char),通过网络发送字节,并struct X在另一方面重新解释它们来简化事情.为此我决定使用gcc的__attribute __((__ packed__)).我已尽最大努力确保正确完成(即我已经考虑了字节序和其他相关问题).
题
除了保证struct X尽可能小,gcc是否保证struct使用__attribute __((__ packed__))定义的保留原始排序?我已经做了相当多的搜索,我还没有找到关于这种保证是否存在的任何文件.
笔记
可以安全地假设发送方和接收方都不会遇到可移植性问题(例如sizeof(int),在服务器上等于sizeof(int)客户端).
我已经看到了关于结构的字节序的一些问题和答案,但它们是关于检测系统的字节序,或者在两个不同的字节序之间转换数据.
但是,如果有一种方法可以强制执行给定结构的特定字节顺序,那么我现在想要的是什么.是否有一些好的编译器指令或其他简单的解决方案,除了重写操作在位域上的很多宏的整个事情?
一般的解决方案会很好,但我也会对特定的gcc解决方案感到满意.
编辑:
感谢所有评论指出为什么强制执行endianness不是一个好主意,但在我的情况下,这正是我需要的.
特定处理器生成大量数据(永远不会改变,它是带有自定义硬件的嵌入式系统),并且必须由在未知处理器上运行的程序(我正在处理)读取.对数据进行字节评估会非常麻烦,因为它包含数百种不同类型的结构,这些结构非常庞大且深入:它们中的大多数都有许多其他巨大的结构层.
改变嵌入式处理器的软件是不可能的.源是可用的,这就是为什么我打算使用该系统的结构而不是从头开始并按字节方式评估所有数据.
这就是为什么我需要告诉编译器它应该使用哪个字节序,无论效率与否都无关紧要.
它不一定是字节序的真正变化.即使它只是一个接口,物理上所有东西都是在处理器自己的字节序中处理的,但我完全可以接受.
我有8个bool变量,我想将它们"合并"成一个字节.
有一个简单/首选的方法来做到这一点?
相反,如何将一个字节解码为8个独立的布尔值?
我认为这不是一个不合理的问题,但由于我无法通过谷歌找到相关文档,它可能是另一个"非你所有直觉都是错误的"案例.
下面的代码可以在Visual C++中成功编译.我喜欢它,它很甜!
#include <stdio.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4201)
#pragma pack(push,1)
#define PACKED
#else
#define PACKED __attribute__ ((__packed__))
#endif
union A {
struct {
int a:1;
int b:2;
int c1:29;
}PACKED;
struct {
int a:1;
int b:2;
int c2:28;
int d:1;
}PACKED;
int val;
}PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#pragma warning(pop)
#endif
#undef PACKED
int main(){
A test;
test.val = 0x1078FFF7;
printf("sizeof(A): %d, test.a: %d.\n", sizeof(A), test.a);
return -1;
}
Run Code Online (Sandbox Code Playgroud)
使用MSC构建的文件输出:
sizeof(A): 4, test.a: -1. …Run Code Online (Sandbox Code Playgroud) 我想知道是否有一个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) 我正在开发一个嵌入式项目(PowerPC目标,Freescale Metrowerks Codewarrior编译器),其中寄存器是内存映射的,并在很好的位域中定义,以便轻松地对各个位标志进行调整.
目前,我们正在使用此功能来清除中断标志并控制数据传输.虽然我还没有注意到任何错误,但我很好奇这是否安全.有没有办法安全地使用位字段,或者我需要将每个包装在DISABLE_INTERRUPTS ... ENABLE_INTERRUPTS?
澄清一下:micro提供的头文件有
union {
vuint16_t R;
struct {
vuint16_t MTM:1; /* message buffer transmission mode */
vuint16_t CHNLA:1; /* channel assignement */
vuint16_t CHNLB:1; /* channel assignement */
vuint16_t CCFE:1; /* cycle counter filter enable */
vuint16_t CCFMSK:6; /* cycle counter filter mask */
vuint16_t CCFVAL:6; /* cycle counter filter value */
} B;
} MBCCFR;
Run Code Online (Sandbox Code Playgroud)
我假设在位域中设置一点不是原子的.这是正确的假设吗?编译器实际为比特域生成了什么样的代码?使用R(原始)字段自己执行掩码可能会更容易记住操作不是原子操作(很容易忘记类似的赋值CAN_A.IMASK1.B.BUF00M = 1不是原子的).
您的建议表示赞赏.
只是想知道关于 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 来读取要读取的字节数。
我发现这两种方法都有其优点:
结构方法:
定义方法:
基本上,我正在寻找一种更智能的方法来处理这些情况。我经常发现自己为每个寄存器和每个位键入了大量令人痛苦的长符号名称,还可能还有掩码和移位(后两个取决于数据类型),结果只使用其中的几个(但讨厌稍后重新定义丢失的符号,这就是我在一个会话中输入所有内容的原因)。不过,我注意到要读/写的字节大小大多是幻数,通常需要并排阅读数据表和源代码才能理解最基本的交互。
我想知道其他人如何处理这些情况?我在网上找到了一些例子,其中人们还在大标题中费力地输入每个寄存器、位等,但没有什么是确定的......但是,在这一点上,上述两个选项似乎都不太聪明:(
我想知道是否可以按位而不是字节进行memcpy?
我正在为带有VLAN标记的以太网帧编写C代码,其中我需要填写VLAN标头属性(PCP-3bits,DEI-1bit,VID-12bits)的不同值.
如何对这些位执行memcpy,或者以位为单位向这些属性填充值的任何其他可能性.
提前致谢 !
我需要以下面的形式处理一些数据:
typedef struct{
unsigned n1 : 12;
unsigned n2 : 12;
unsigned n3 : 12;
unsigned n4 : 1;
unsigned n5 : 35;
} data;
Run Code Online (Sandbox Code Playgroud)
我确保它们总共可以计算9个字节.
但他们没有..将该结构的9个字节写入文件并将其读回不会恢复所有数据,并sizeof(data)返回16.
这里的问题是什么?
我收到了错误
error: aggregate value used where an integer was expected
Run Code Online (Sandbox Code Playgroud)
在编译此代码时:
#include <stdio.h>
typedef unsigned long U32;
typedef struct hello_s
{
U32 a:8;
U32 b:24;
}hello_t;
int main()
{
hello_t str;
U32 var;
str.a = 0xAA;
str.b = 0xAAA;
var = (U32)str;
printf("var : %lX\n", var);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有人可以解释错误的含义,以及我做错了什么.
编辑:我知道这是一个愚蠢的事情.我想知道的是为什么编译器会为此而哭泣.为什么它只能将前32位分配给整数.
我有这个代码 - http://ideone.com/sXhWxf
#include <stdio.h>
int main(void) {
struct bitfield{
unsigned a:5;
unsigned c:5;
unsigned b:6;
} bit = {1,3,3};
char *p = (char*)&bit;
printf("%d\n",*p);
p++;
printf("%d\n",*p);
// I assumed that the bits are laid out in the below order in the memory.
// Spaces are just for clarity
// 00001 00011 000011
// Also, I asumed that the 'char' will take 8 bits. But I can't understand output.
// According to me the output should be - 8 195 …Run Code Online (Sandbox Code Playgroud) c ×10
c++ ×5
bit-fields ×3
gcc ×3
struct ×2
bit-packing ×1
boolean ×1
casting ×1
embedded ×1
endianness ×1
ethernet ×1
i2c ×1
low-level ×1
memcpy ×1
memory ×1
networking ×1
output ×1
powerpc ×1
unions ×1