Неожиданные результаты при создании 32-битного целого числа из массива байтов

У меня возникли проблемы с созданием 32-битного целого числа из 4-байтового массива. В следующем полном, минимальном и проверяемом примере преобразование массива байтов, содержащего 0x00, 0x04, 0x04F, 0x45, приводит к 4F45 (ожидаемый результат будет 44F45). Должно быть, я упускаю из виду что-то фундаментальное... Кто-нибудь может увидеть, где я ошибся?

void setup()
{
    Serial.begin(9600);
    while(!Serial);
}

void loop()
{
    uint8_t bytes[4] = {0x00, 0x04, 0x4F, 0x45}; //00044F45
    int32_t theInt = byteArrayToInt32(bytes);
    Serial.println(theInt, HEX); // Печать 4F45
    delay(250);
}

uint32_t byteArrayToInt32(uint8_t* bytes)
{
    uint32_t i = 0;
    i |= bytes[0] << 24;
    i |= bytes[1] << 16;
    i |= bytes[2] << 8;
    i |= bytes[3];
    return i;
}

, 👍0

Обсуждение

@jsotola каким образом?, @You'reAGitForNotUsingGit

@jsotola Я повторно протестировал его как uint32_t, без разницы :(, @You'reAGitForNotUsingGit


1 ответ


Лучший ответ:

1

Проблема в том, что вы пытаетесь сдвинуть uint8_t более чем на 8 бит, а затем выполняете ИЛИ с помощью int32_t.

Вы должны преобразовать uint8_t в int32_t перед выполнением сдвига.

void setup()
{
    Serial.begin(9600);
    while(!Serial);
}

void loop()
{
    uint8_t bytes[4] = { 0x00, 0x04, 0x4F, 0x45}; //00044F45
    int32_t theInt = byteArrayToInt32(bytes);
    Serial.println(theInt, HEX); // Печать 4F45
    delay(1000);
}

int32_t byteArrayToInt32(uint8_t* bytes)
{
    int32_t i = 0;
    i |= (int32_t) bytes[0] << 24;
    i |= (int32_t) bytes[1] << 16;
    i |= (int32_t) bytes[2] <<  8;
    i |= (int32_t) bytes[3];
    return i;
}
,

Обратите внимание, что если старший бит bytes[0] установлен, то (int32_t) bytes[0] << 24 сдвинет его на знаковый бит, что является неопределенным поведением. Безопаснее приводить к uint32_t, который, в свою очередь, можно безопасно присвоить int32_t., @Edgar Bonet

Хм, то, как вы предложили, решает проблему, однако я очень озадачен тем, почему сдвиг влево на 8 бит работал изначально?, @You'reAGitForNotUsingGit

похоже, что функция сдвига влево использует 16-битный буфер .... возможно, потому, что он использует тот же код для 16-битных сдвигов, @jsotola