我读了一堆输入(传感器),我得到每个传感器的0(关闭)或1(开启)。我在char *中获得这些值,其中我得到了所有传感器的结果。每个传感器都有1位。
当我想在我的代码中使用这些值时,我觉得将这个结果与另一个带有我感兴趣的一位字符的char结果并不是一个好主意,因为代码变得非常臃肿。
相反,我想要制作一个像这样的结构:
struct sensors {
unsigned int Sensor0:1;
unsigned int Sensor1:1;
unsigned int Sensor2:1;
unsigned int Sensor3:1;
unsigned int Sensor4:1;
unsigned int Sensor5:1;
unsigned int Sensor6:1;
unsigned int Sensor7:1;
}
struct sensors s1;
memcpy(buf, (char*)&sensors, 1);
但是从我读过的内容中,结构可能不会在内存中相互保存每个组件,并且可能会在其间插入填充和其他内容,这使得它不再适用。
我错了吗?有没有更好的方法来做到这一点?
答案 0 :(得分:4)
根据您当前的struct sensors
定义,编译器将插入额外的填充,因为int
具有对齐要求,通常在sizeof(int)
边界上。此外,int
必须宽于char
,因此它可以容纳超过8个标志,这是您不需要的。
如果你这样声明(改为使用unsigned char
),则应该没有填充,因为char
具有最不严格的对齐要求:
struct sensors {
unsigned char Sensor0:1;
unsigned char Sensor1:1;
unsigned char Sensor2:1;
unsigned char Sensor3:1;
unsigned char Sensor4:1;
unsigned char Sensor5:1;
unsigned char Sensor6:1;
unsigned char Sensor7:1;
}
这可能不仅适用于CHAR_BIT != 8
的非常奇怪的平台。
答案 1 :(得分:2)
添加到Blagovest的答案:
比特场方法看似合理。但是,您必须指示编译器不在字段之间引入填充。对于GCC,这是通过在结构定义之后放置__attribute__ ((packed))
来完成的,如下所示:
struct sensors {
unsigned char Sensor0:1;
unsigned char Sensor1:1;
unsigned char Sensor2:1;
unsigned char Sensor3:1;
unsigned char Sensor4:1;
unsigned char Sensor5:1;
unsigned char Sensor6:1;
unsigned char Sensor7:1;
} __attribute__ ((packed));
请注意,4.4之前的GCC用于为char
字段引入填充,而不管此指令;有关详细信息,请参阅the documentation on warning option -Wpacked-bitfield-compat
。
答案 2 :(得分:0)
如果您想要超级安全,可以使用具有一位设置的字符进行AND。您可能希望使用数组而不是结构来执行此操作。你可以将它包装成一个漂亮的循环,它根本没用多少。
但是,任何理智的C编译器都会将无符号整数放在连续的内存中,所以做某种类似的复制应该是安全的。当存在不同大小的类型时,编译器通常只会添加额外的填充。不幸的是我不知道这是否适合您,因为你有命令memcpy(buf,(char *)& sensors,1)会将你的传感器数据字节复制到第一个整数 - 这不是你想要的。
答案 3 :(得分:0)
我会使用memcpy()
来访问Blagovest Buyukliev answer中定义的数据,而不是union
:
union combSensors {
unsigned char all_fields;
struct sensors field_by_field;
}