我要面对的问题如下.我有一个这样的 struct :

typedef struct 
{
    uint8 nibble_1 : 4;
    uint8 nibble_2 : 4;
    uint8 data_1;
    uint8 data_2;
    uint8 data_3;
} NibbleStruct;

它是用于CAN通信的32位消息.

在代码中,我有以下内容:

...
NibbleStruct nibble_struct;
uint8 nibble_to_assign = 0U;
nibble_struct.nibble_1 = nibble_to_assign;
...

我需要保留GCC(Gnu99)标志-Werror=conversion,但这会给出错误消息:

File_name.c错误:从‘uint8’转换为‘unsign char:4’可能会更改其值[-Werror=转换]|

我试着用像这样的东西来选角

...
nibble_struct.nibble_1 = (uint8:4) nibble_to_assign;
...

...
nibble_struct.nibble_1 = (uint8) nibble_to_assign : 4;
...

但这并不令人惊讶,因为它没有编译.

有没有办法将变量nibble_to_assign 转换为 struct 体的nibble nibble_1?或在 struct 外部的代码中声明半字节.

推荐答案

建议将ISO C标准uint8_t的"车库标准"uint8go 掉.

这里有几件事要记住:

  • C标准不支持字符类型为/uint8_t的位域--这是一个不可移植的编译器扩展.
  • 因此,C标准也不包括非标准位字段成员的类型转换和提升.
  • -Wconversion是一个不稳定的编译器选项,容易出现误报和误导性诊断.它很适合用于压力测试/代码审查,但不应该包含在您的正常构建中.

在这种情况下,-Wconversion抱怨的问题是,显然无法预测uint8_t值是否适合4比特位字段.

我可以通过强迫一个未签名的提升到unsigned int来沉默它:

nibble_struct.nibble_1 = nibble_to_assign & 0xFu;

但请注意, struct 或位域都不是特别适合或推荐用于硬件或数据协议建模. struct 中可能有填充字节或填充比特.如果坚持使用 struct ,则可能必须编写序列化/反序列化 routine 以避免填充问题.为了处理字符顺序,您可能无论如何都必须这样做,因为Can最常(但不总是)使用高字节顺序.

C++相关问答推荐

漏洞仅出现在FreeBSD上,但在Windows、Linux和MacOS上运行得非常好

从C函数调用asm函数时生成错误的BLX指令(STM32H753上的gcc)

为什么在Linux(特别是Ubuntu 20.04LTS)上,POSIX共享内存对象在重启后仍然存在,然后突然变成了根用户?

当多个线程在C中写入相同的文件描述符时,如何防止争用情况?

将指针作为参数传递给函数

C语言编译阶段与翻译阶段的关系

是否可以使用指针算法在不对齐的情况下在 struct 中相同类型的字段的连续序列之间移动?

Clang警告称,`ffi_type`与`sizeof`不兼容

如何在C++中安全地进行浮点运算

C11/C17标准允许编译器清除复合文字内存吗?

是否定义了此函数的行为?

Zlib:解压缩大文件导致";无效代码长度设置";错误

安全倒计时循环

C:如何将此代码转换为与数组一起使用?

使用正则表达式获取字符串中标记的开始和结束

在printf()中用%.*S格式填充长度为0的字符串是否会调用任何UB?如果是,是哪一个?

如何打印循环调度问题的时间表

将数组中的所有元素初始化为 struct 中的相同值

将数组返回到链表

我该如何处理这个 C 90 代码中的内存泄漏?