使用位域运算符时的位填充

时间:2015-10-26 06:51:54

标签: c struct bit-fields can-bus

我的目标是实现写入标准CAN帧信号的功能。标准CAN帧包含以下信号:

  • ID:11位
  • rtr:1bit
  • reserved_0:1位
  • reserved_1:1位
  • DLC:4位
  • 数据:8个字节

这是我对CAN框架的表示

typedef union
{
unsigned char tab[10];
struct
{
    unsigned char id_8_10:3; //ID: bit 8==>10
    unsigned char id_4_7:4; //ID: bit 4==>7
    unsigned char id_0_3:4; //ID: bit 0==>3
    unsigned char rtr:1;
    unsigned char reserved0:1;
    unsigned char reserved1:1;
    unsigned char dlc:4;
    unsigned char tabData[8];
 }bBit;
}tCanFrame;

Write函数如下:

void IL_Wr_id_8_10(unsigned char ubVal)
{
 ((tCanFrame*)(&tabFrame))->bBit.id_8_10 = (unsigned int)(ubVal);
}

void IL_Wr_id_4_7(unsigned char ubVal)
{
 ((tCanFrame*)(&tabFrame))->bBit.id_4_7 = (unsigned int)(ubVal);
}

void IL_Wr_id_0_3(unsigned char ubVal)
{
((tCanFrame*)(&tabFrame))->bBit.id_0_3 = (unsigned int)(ubVal);
}

void IL_Wr_rtr(unsigned char ubVal)
{
 ((tCanFrame*)(&tabFrame))->bBit.rtr =(ubVal);
}

void IL_Wr_reserved1(unsigned char ubVal)
{

 ((tCanFrame*)(&tabFrame))->bBit.reserved1 =(ubVal);

}

void IL_Wr_dlc(unsigned char ubVal)
{

 ((tCanFrame*)(&tabFrame))->bBit.dlc =(ubVal);

}

void IL_Wr_data(unsigned char* ubVal)
{

 memcpy(((tCanFrame*)(&tabFrame))->bBit.tabData,ubVal,8);

}

在主要部分我试图给信号赋值并打印它们,但遗憾的是它似乎插入了填充位。

这是主要的:

int main()
{
 int i;
 IL_Wr_id_8_10(0x7);
 IL_Wr_id_4_7(0x00);
 IL_Wr_id_0_3(0x0F);
 IL_Wr_rtr(0x00);
 IL_Wr_reserved0(0x0);
 IL_Wr_reserved1(0xFF);
 IL_Wr_dlc(0x0F);
 IL_Wr_data(tableauDonnee);

 for (i=0;i<18;i++)
 {
    printf("Byte %i : %s \n",i,byte_to_binary(tabFrame[i]));
 }
 return 0;
}

结果如下:

Byte 0 : 0000.0111 // the result should be Byte 0 : 1000.0111 
Byte 1 : 0100.1111 // the result should be Byte 1 : 1110.0111
....

您认为有什么问题,您有什么想法解决这个问题吗?

3 个答案:

答案 0 :(得分:0)

您的解决方案无法移植。

您无法可靠地使用位域:内存中字段的实际布局是实现定义的,通常取决于目标架构字节顺序。

如果您的编译器/架构组合的布局恰好正确,您确定实际位布局吗?您在.footer { position: absolute; margin-bottom: 0px; background: rgba(0, 0, 0, 0.6); color: #FFF; width: 100%; height: auto; } 数组之前定义18位:将插入至少6个填充位,以便在字节边界上对齐tabData,产生一个11字节结构,您似乎认为它是只有10个字节长。

答案 1 :(得分:0)

您的位字段数据的总大小为18位,因此使用&#39; int&#39;或者&#39; unsigned int&#39;将正常工作以表示您的标题数据。

typedef union
{
unsigned char tab[10];
struct
{
    int id_8_10:3; //ID: bit 8==>10
    int id_4_7:4; //ID: bit 4==>7
    int id_0_3:4; //ID: bit 0==>3
    int rtr:1;
    int reserved0:1;
    int reserved1:1;
    int char dlc:4;
    unsigned char tabData[8];
 }bBit;
}tCanFrame;

如果是位字段,

struct
{
    data_type [member_name] : width;
};  

&#39; data_type&#39;的大小使用位字段数据成员指定的边界考虑因素。

在你的情况下, id_8_10(3比特),id_4_7(4比特)和id_0_3(4比特)加起来超过8比特的11比特。因此,id_0_3(4比特)被分配在第二字节中。第一个字节仅包含id_8_10(3位)和id_4_7(4位)= 7位+ 1位未使用。

使用&#39; int&#39;或者&#39; unsigned int&#39;会有所帮助。

注意::基于你的main(),字节1预计为1110.0111,而不是
字节1:..... //结果应为Byte 1:0010.0111&lt; - 如您所示。

答案 2 :(得分:0)

我选择实现自己的功能:

/*function: copy_bits
 description: copy nbBitsToCopy bits from srcAdress to destAdress starting from a specific bit start_bit
 destAdress: destination address
 start_bit:the bit in the destination where to paste data
 srcAdress:source address
 nbBitsToCopy: Number of bit to copy from source
*/
void copy_bits(unsigned char* destAdress , unsigned char start_bit, unsigned char *srcAdress, unsigned char nbBitsToCopy)
{
unsigned int dest_Cursor_Byte;
unsigned int dest_Cursor_Bit;
unsigned int src_Cursor_Byte;
unsigned int src_Cursor_Bit;
unsigned int nbCopiedBits=0;

//Initialisation of cursors
dest_Cursor_Byte=start_bit/8;
dest_Cursor_Bit =start_bit%8;

src_Cursor_Byte=0;
src_Cursor_Bit=0;

while (nbCopiedBits<nbBitsToCopy)
{
    if (CHECK_BIT(srcAdress[src_Cursor_Byte],src_Cursor_Bit,1))
    {
        SET_BIT_VALUE(destAdress[dest_Cursor_Byte],dest_Cursor_Bit,1);
    }

    else
    {
        SET_BIT_VALUE(destAdress[dest_Cursor_Byte],dest_Cursor_Bit,0);
    }
    nbCopiedBits++;
    start_bit++;

    //Update cursors
    dest_Cursor_Byte=start_bit/8;
    dest_Cursor_Bit =start_bit%8;

    src_Cursor_Bit=nbCopiedBits%8;
    src_Cursor_Byte=nbCopiedBits/8;
 }
}

欢迎你发表评论