Значение переменной отличается, когда оно печатается после структурного присвоения и когда печатается без структурного присвоения - PullRequest
0 голосов
/ 15 октября 2019

Я не знаю, как поставить соответствующий заголовок, чтобы объяснить проблему. Поэтому не стесняйтесь, если у вас есть более информативный заголовок для редактирования.

Чтобы понять проблему, позвольте мне объяснить, что я делаю.

Я создал структуру следующим образом:

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 ]

1 голос
/ 15 октября 2019

Согласно сноске 128 к 2018 году, определяется реализацией, является ли битовое поле, определенное с помощью int, как в int YWheelSpeed, подписанным или неподписанным. Поскольку ваша реализация показывает отрицательное значение для него, предположительно, оно подписано, и, следовательно, как 16-разрядное целое число со знаком, оно может представлять значения от −32 768 до 32 767.

Мы также можем вывести, что int в вашей реализации более 16 бит, вероятно, 32 бита (из-за того, что «65535» печатается в одном случае, когда int y печатается с «% d»).

Рассмотрим это назначение:

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

В этом выражении readBuff[33] и readBuff[32] преобразуются в int с помощью обычных повышений . 0x00FF также является int.

. Если предположить, что readBuff[33] равно 255, а readBufff[32] равно 159 (что равно 2 8 -97), то значениевыражение на правой стороне = составляет 65 439 (то есть 2 16 -97). В присваивании правый операнд преобразуется в тип левого операнда, который представляет собой 16-разрядное целое число со знаком. В этом случае значение 65 439 не может быть представлено 16-разрядным целым числом со знаком. C 2018 6.3.1.3 3 говорит нам, что «либо результат определяется реализацией, либо повышается сигнал, определяемый реализацией».

Обычной реализацией этого преобразования является получение результата по модулю 2 16 или, что то же самое, переосмыслить 16 младших битов int как 16-разрядное целое число с дополнением до двух. Это дает −97. Поскольку ваша реализация впоследствии показала -97 для значения, вероятно, именно это и сделала ваша реализация.

Таким образом, dataOut->fields.YWheelSpeed присваивается значение -97. Когда позже оно печатается с:

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

, тогда аргументы по умолчанию для аргументов , которые включают обычные целочисленные продвижения, преобразуют temp.fields.YWheelSpeed из 16-разрядного целого числа со знаком со значением −97в int со значением −97, и печатается «-97».

В противоположность, предположим, что (readBuff[33] & 0x00FF) << 8 | (readBuff[32] & 0x00FF) печатается с %d. Как мы видели выше, значение этого выражения составляет 65 439, поэтому должно быть напечатано «65439».

Вопрос гласит:

Теперь вот что, если я напечатаю (readBuff[27] & 0x00FF) << 8 | (readBuff[26] & 0x00FF), что соответствует тому, что было заполнено в переменной скорости колеса Y,… оно печатает максимальное значение беззнакового символа (65 535).

Однако (readBuff[27] & 0x00FF) << 8 | (readBuff[26] & 0x00FF) не является значением, котороебыл назначен на YWheelSpeed, который предположительно является «переменной скорости колеса Y». YWheelSpeed было присвоено из readBuff элементов 32 и 33, а не 26 и 27. Таким образом, мы не должны удивляться, что вместо 65 439 печатается какое-то другое значение.

1 голос
/ 15 октября 2019

Вероятно, у вас 32-битный int, поэтому при инициализации никогда не устанавливается знаковый бит. Но поле структуры составляет всего 16 бит и будет расширено знаком, когда оно преобразуется в int для вызова printf().

...