Arduino bitwise operations different than vanilla C?

I'm doing a project that involves bitwise operations and there appears to be a difference when running bitwise operations on a vanilla C compiler versus on Arduino

C Example:

#include <stdio.h>
#include "stdint.h"

uint32_t u8_to_u32(uint8_t bytes[4]) {
    printf("bytes: %d %d %d %d \n", bytes[0], bytes[1], bytes[2], bytes[3]);
  uint32_t u32 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
  return u32;
}

void u32_to_u8(uint32_t u32, uint8_t u8[4]) {
  u8[0] = (u32 & 0xff000000) >> 24;
  u8[1] = (u32 & 0x00ff0000) >> 16;
  u8[2] = (u32 & 0x0000ff00) >> 8;
  u8[3] = u32 & 0x000000ff;
}

int main()
{
    printf("Hello World\n");

    uint32_t  timestamp = 1638794023;
    uint8_t bytes[4];
    u32_to_u8(timestamp, bytes);
    uint32_t converted = u8_to_u32(bytes);
    printf("timestamp %d\n", timestamp);
    
    printf("converted %d\n", converted);
    return 0;
}

Arduino Example:

uint32_t u8_to_u32(uint8_t bytes[4]) {
  Serial.print("bytes: ");Serial.print(bytes[0]);Serial.print(" ");Serial.print(bytes[1]);Serial.print(" ");Serial.print(bytes[2]);Serial.print(" ");Serial.print(bytes[3]);Serial.print(" ");
  uint32_t u32 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
  return u32;
}

void u32_to_u8(uint32_t u32, uint8_t u8[4]) {
  u8[0] = (u32 & 0xff000000) >> 24;
  u8[1] = (u32 & 0x00ff0000) >> 16;
  u8[2] = (u32 & 0x0000ff00) >> 8;
  u8[3] = u32 & 0x000000ff;
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Hello World");

  uint32_t  timestamp = 1638794023;
  uint8_t bytes[4];
  u32_to_u8(timestamp, bytes);
  uint32_t converted = u8_to_u32(bytes);
  Serial.print("timestamp: ");Serial.println(timestamp);
  Serial.print("converted: ");Serial.println(converted);
}

void loop() {
  // put your main code here, to run repeatedly:

}

C output:

Hello World
timestamp 1638794023
data: 97 174 3 39 
converted 1638794023

Arduino output:

Hello World
bytes: 97 174 3 39
timestamp: 1638794023
converted: 807

Is anyone aware of some consideration in Arduino that I am not understanding that might result in this output? Is my Arduino broken?

bytes[0] has type uint8_t, which is promoted to an int, which is 16 bits wide on AVR, so you cannot shift it to the left by 24 bits. Cast it to uint32_t before shifting.

2 Likes

cast it to 32? Or do you mean cast it to 8?

No, cast it to uint32_t:

static_cast<uint32_t>(bytes[0]) << 24

That seems excessively verbose. A standard C cast should work fine:
((uint32_t)bytes[0])<<24
Note that you need this for the 16bit shift as well.

Note: If you had set "Compiler warnings:" to "All" in Preferences you would have gotten a helpful warning message that the shift operation was going to result in a zero.

1 Like