Random high byte when double converted to signed 16 int and sent over BLE

I am taking over a firmware Bluetooth project and am reading the code that is having some issues. Below is a snippet from a BLE characteristic read callback.  Here a double is being converted to a 16 bit int. I am not sure why it is converted to a long first, but anyway the problem is that there seems to be a random higher byte when it should be 0

For example, when force is equal to 250, I would expect the value seen in nrfConnect to be 0x00-FA, but the value received has the first byte with a value that makes no sense and it changes.

For example I receive 0x34-FA, 0x68-FA, etc. FA is 250 so that is correct, but the higher byte is seemingly random.

The same goes for when force is 0, nrfConnect shows

0x22-00, 0x10-00, and so on with a random higher byte when I would expect 0x00-00



//read force levels
double force = read_force();

//convert to 16 bit int
long val_long = (long) force;
int16_t val16 = (int16_t) val_long;
int16_t *val16_ptr = &val16;

//dispatch value
return bt_gatt_attr_read(conn, attr, buf, len, offset, val16_ptr,
sizeof(*val16_ptr));

Parents
  • A double is 8 bytes and a int16_t is 2 bytes. 

    If you cast a double to a int16_t you are going to truncate the decimal value.

    double d = 250.55;
    int16_t i = (int16_t)d; //i = 250

    If you are casting a `double*` to a `*int16_t*` and tying to dereference, you are going to get undefined behavior because its going to read 8 bytes from something that only has 2 bytes, so the value could be anything. You are probably doing something similar to this if your value changes on different runs of the application.

    int16_t i = 250;
    double d = *(double*)&i; // Undefine behavior. The value of i could be anything

    If you go the other way and cast a `*int16_t*` to a double*` and dereference, you will get a seemingly nonsensical value but it should stay the same between runs. This is because the memory layout of int_16 and double are not the same and you are reading only 2 bytes of the double.

    double d = 250.55;
    int16_t i = *(int16_t*)&d;

  • Hi.  I don't understand this scenario: "If you are casting a `double*` to a `*int16_t*` and tying to dereference, you are going to get undefined behavior because its going to read 8 bytes from something that only has 2 bytes, so the value could be anything."

    My code is pasted in the original post.  I don't dereference a pointer at any time.  bt_gatt_attr_read takes in a pointer and the number of bytes (2).  It's not reading more than 2 bytes, but the high byte that is read is seemingly random.

Reply
  • Hi.  I don't understand this scenario: "If you are casting a `double*` to a `*int16_t*` and tying to dereference, you are going to get undefined behavior because its going to read 8 bytes from something that only has 2 bytes, so the value could be anything."

    My code is pasted in the original post.  I don't dereference a pointer at any time.  bt_gatt_attr_read takes in a pointer and the number of bytes (2).  It's not reading more than 2 bytes, but the high byte that is read is seemingly random.

Children
Related