在结构分配后打印变量值和在不进行结构分配的情况下打印时变量值是不同的

时间:2019-10-15 07:57:20

标签: c struct casting printf shift

我不知道如何添加适当的标题来解释问题。因此,如果您需要更多内容的标题进行编辑,请放心。

要了解该问题,请让我解释一下我在做什么。

我创建了一个如下结构:

typedef union __attribute__ ((__packed__)) adcs_measurements_t
{
    unsigned char raw[72];
    struct __attribute__ ((__packed__)) //191
    {
        int magneticFieldX : 16;
        int magneticFieldY : 16;
        int magneticFieldZ : 16;
        int coarseSunX : 16;
        int coarseSunY : 16;
        int coarseSunZ : 16;
        int sunX : 16;
        int sunY : 16;
        int sunZ : 16;
        int nadirX : 16;
        int nadirY : 16;
        int nadirZ : 16;
        int XAngularRate : 16;
        int YAngularRate : 16;
        int ZAngularRate : 16;
        int XWheelSpeed : 16;
        int YWheelSpeed : 16;
        int ZWheelSpeed : 16;
        int star1BX : 16;
        int star1BY : 16;
        int star1BZ : 16;
        int star1OX : 16;
        int star1OY : 16;
        int star1OZ : 16;
        int star2BX : 16;
        int star2BY : 16;
        int star2BZ : 16;
        int star2OX : 16;
        int star2OY : 16;
        int star2OZ : 16;
        int star3BX : 16;
        int star3BY : 16;
        int star3BZ : 16;
        int star3OX : 16;
        int star3OY : 16;
        int star3OZ : 16;
    } fields;
} adcs_measurements_t;

我通过调用以下函数填充结构:

void adcsTM191_measurements(adcs_measurements_t* dataOut)
{
    int pass;
    unsigned char TMID = 191;
    unsigned char readBuff[72] = {0};
    pass = I2C_write(ADCS_ADDR, &TMID, 1);
    if(pass != 0)
    {
        printf("write error %d\n", pass);
    }
    pass = I2C_read(ADCS_ADDR, readBuff, 72);
    if(pass != 0)
    {
        printf("read error %d\n", pass);
    }

    dataOut->fields.magneticFieldX = (readBuff[1] & 0x00FF) << 8 | (readBuff[0] & 0x00FF);
    dataOut->fields.magneticFieldY = (readBuff[3] & 0x00FF) << 8 | (readBuff[2] & 0x00FF);
    dataOut->fields.magneticFieldZ = (readBuff[5] & 0x00FF) << 8 | (readBuff[4] & 0x00FF);
    dataOut->fields.coarseSunX = (readBuff[7] & 0x00FF) << 8 | (readBuff[6] & 0x00FF);
    dataOut->fields.coarseSunY = (readBuff[9] & 0x00FF) << 8 | (readBuff[8] & 0x00FF);
    dataOut->fields.coarseSunZ = (readBuff[11] & 0x00FF) << 8 | (readBuff[10] & 0x00FF);
    dataOut->fields.sunX = (readBuff[13] & 0x00FF) << 8 | (readBuff[12] & 0x00FF);
    dataOut->fields.sunY = (readBuff[15] & 0x00FF) << 8 | (readBuff[14] & 0x00FF);
    dataOut->fields.sunZ = (readBuff[17] & 0x00FF) << 8 | (readBuff[16] & 0x00FF);
    dataOut->fields.nadirX = (readBuff[19] & 0x00FF) << 8 | (readBuff[18] & 0x00FF);
    dataOut->fields.nadirY = (readBuff[21] & 0x00FF) << 8 | (readBuff[20] & 0x00FF);
    dataOut->fields.nadirZ = (readBuff[23] & 0x00FF) << 8 | (readBuff[22] & 0x00FF);
    dataOut->fields.XAngularRate = (readBuff[25] & 0x00FF) << 8 | (readBuff[24] & 0x00FF);
    dataOut->fields.YAngularRate = (readBuff[27] & 0x00FF) << 8 | (readBuff[26] & 0x00FF);
    dataOut->fields.ZAngularRate = (readBuff[29] & 0x00FF) << 8 | (readBuff[28] & 0x00FF);
    dataOut->fields.XWheelSpeed = (readBuff[31] & 0x00FF) << 8 | (readBuff[30] & 0x00FF);
    dataOut->fields.YWheelSpeed = (readBuff[33] & 0x00FF) << 8 | (readBuff[32] & 0x00FF);
    dataOut->fields.ZWheelSpeed = (readBuff[35] & 0x00FF) << 8 | (readBuff[34] & 0x00FF);
    dataOut->fields.star1BX = (readBuff[37] & 0x00FF) << 8 | (readBuff[36] & 0x00FF);
    dataOut->fields.star1BY = (readBuff[39] & 0x00FF) << 8 | (readBuff[38] & 0x00FF);
    dataOut->fields.star1BZ = (readBuff[41] & 0x00FF) << 8 | (readBuff[40] & 0x00FF);
    dataOut->fields.star1OX = (readBuff[43] & 0x00FF) << 8 | (readBuff[42] & 0x00FF);
    dataOut->fields.star1OY = (readBuff[45] & 0x00FF) << 8 | (readBuff[44] & 0x00FF);
    dataOut->fields.star1OZ = (readBuff[47] & 0x00FF) << 8 | (readBuff[46] & 0x00FF);
    dataOut->fields.star2BX = (readBuff[49] & 0x00FF) << 8 | (readBuff[48] & 0x00FF);
    dataOut->fields.star2BY = (readBuff[51] & 0x00FF) << 8 | (readBuff[50] & 0x00FF);
    dataOut->fields.star2BZ = (readBuff[53] & 0x00FF) << 8 | (readBuff[52] & 0x00FF);
    dataOut->fields.star2OX = (readBuff[55] & 0x00FF) << 8 | (readBuff[54] & 0x00FF);
    dataOut->fields.star2OY = (readBuff[57] & 0x00FF) << 8 | (readBuff[56] & 0x00FF);
    dataOut->fields.star2OZ = (readBuff[59] & 0x00FF) << 8 | (readBuff[58] & 0x00FF);
    dataOut->fields.star3BX = (readBuff[61] & 0x00FF) << 8 | (readBuff[60] & 0x00FF);
    dataOut->fields.star3BY = (readBuff[63] & 0x00FF) << 8 | (readBuff[62] & 0x00FF);
    dataOut->fields.star3BZ = (readBuff[65] & 0x00FF) << 8 | (readBuff[64] & 0x00FF);
    dataOut->fields.star3OX = (readBuff[67] & 0x00FF) << 8 | (readBuff[66] & 0x00FF);
    dataOut->fields.star3OY = (readBuff[69] & 0x00FF) << 8 | (readBuff[68] & 0x00FF);
    dataOut->fields.star3OZ = (readBuff[71] & 0x00FF) << 8 | (readBuff[70] & 0x00FF);

}

最后我打印,例如YWheelSpeed

adcsTM191_measurements(&temp);  
printf("structure y wheel speed is: %d \n", temp.fields.YWheelSpeed);

此值应打印一个负值,并且可以:

structure y wheel speed is: -97

现在这是事情,如果我打印(readBuff[27] & 0x00FF) << 8 | (readBuff[26] & 0x00FF),它对应于Y车轮速度变量中填充的内容,则adcsTM191_measurements(adcs_measurements_t* dataOut)内的任何地方都不会打印此负值。而是打印无符号字符的最大值(65,535‬)。

int y = (int) (readBuff[33] & 0x00FF) << 8 | (readBuff[32] & 0x00FF);
printf("inside struct y is: %d", y);

我期望存储在结构内部会进行某种隐式强制转换,因此它将按预期输出负值。怎么样了?在不使用结构的情况下如何打印正确的值?

2 个答案:

答案 0 :(得分:1)

您可能有32位int,所以初始化永远不会设置符号位。但是结构字段只有16位,并且在将其int调用转换为printf()时将进行符号扩展。

答案 1 :(得分:1)

根据C 2018脚注128,由int定义的位域(如int YWheelSpeed中定义的)是实现定义的还是未签名的。由于您的实现为此显示一个负值,因此大概是带符号的,因此,作为一个16位带符号整数,它可以表示从-32,768到32,767的值。

我们还可以推断出,您实现中的int多于16位,可能是32位(这是因为在一种情况下,当int y上打印有“%d”时,会打印“ 65535” ”)。

考虑此作业:

dataOut->fields.YWheelSpeed = (readBuff[33] & 0x00FF) << 8 | (readBuff[32] & 0x00FF);`

在此表达式中,常规促销readBuff[33]readBuff[32]转换为int0x00FF也是int

如果我们假设readBuff[33]为255而readBufff[32]为159(即2 8 −97),则表达式{的右边的值{1}}为65439(即2 16 −97)。在分配中,右操作数将转换为左操作数的类型,即16位带符号整数。在这种情况下,值65,439不能用16位带符号整数表示。 C 2018 6.3.1.3 3告诉我们“结果是实现定义的,还是引发实现定义的信号。”

此转换的常见实现是产生模2 16 的结果,或者等效地将=的16个低位重新解释为2的补码16位整数。这产生−97。由于您的实现随后将值显示为-97,因此大概就是您的实现了。

因此,int被分配值为-97。以后再打印时:

dataOut->fields.YWheelSpeed

然后使用默认参数推广(其中包括通常的整数提升),将printf("structure y wheel speed is: %d \n", temp.fields.YWheelSpeed); 从带符号的-97的16位整数转换为值为-97的temp.fields.YWheelSpeed 97,并打印“ -97”。

相反,假设int(readBuff[33] & 0x00FF) << 8 | (readBuff[32] & 0x00FF)打印。正如我们在上面看到的,该表达式的值是65439,因此应打印“ 65439”。

问题指出:

  

现在这是事情,如果我打印%d,它对应于Y车轮速度变量中填充的内容,…它将打印无符号字符的最大值(65,535‬)。

但是,(readBuff[27] & 0x00FF) << 8 | (readBuff[26] & 0x00FF)不是分配给(readBuff[27] & 0x00FF) << 8 | (readBuff[26] & 0x00FF)的值,它可能是“ Y车轮速度变量”。 YWheelSpeed是由YWheelSpeed元素32和33分配的,而不是26和27分配的。因此,如果打印出一些不同的值而不是65439,我们就不会感到惊讶。

相关问题