I am wondering what the second line of code does:

int16_t GyX;

Also, how can I write the GyX value to EEPROM?

From what I understand, int16_t is a two-bytes value. The Wire.read() returns a single byte. The <<8 shifts the bits by one byte to the left in order to read the higher order bits, and the last part writes the next wire read (lower order bits). Basically, reads wire twice and stores those values in the int. Is that correct?

For the writing, would

EEPROM.write(addr, GyX >> 8); 
EEPROM.write(addr, GyX & 0xff);

do the trick? (First line records the higher order bits, while second records the lower order ones)


@PetioPetrov, Arduino has macros to make it easier: highByte, lowByte, and word.

You don't have to split and combine bytes and words. The EEPROM.put and EEPROM.get can write and read two bytes if you want to. It's all documented in the reference of EEPROM.

There is a lot going on in this piece of code:

int16_t GyX;

Shifting a single byte 8 bits to the left would be wrong. However, the Wire.read returns an integer and the GyX is an integer. Therefor the compiler uses integers for everything and shifting 8 bits to the left is valid.
At this moment with the current Arduino and avr-gcc compiler version, it will call the Wire.read for the high byte first and then the Wire.read for the low byte. That is pure luck as @EdgarBonet has corrected me below. In the c++ language there is no specified order of calling functions.
The bitwise 'OR' with the '|' could be a problem when there was no data and -1 was returned by Wire.read.

  • 1
    Even with the most extreme optimizations, the order is in this situation still from left to right”. No. The order is unspecified. See Order of evaluation in C++. – Edgar Bonet Jun 27 '17 at 20:05
  • @EdgarBonet, Thanks for the correction. I thought that when a call was made to the same function, it would always work. But the C++ language explicitly has defined that there is no specified order. I will try to remember that. – Jot Jun 27 '17 at 20:29


This is a bug. It reads two bytes from the I2C bus and builds a 16-bit number from them. One of the bytes (we don't know which one) will be the most significant byte of the result. The other byte will be the least significant byte.

This instruction is likely to work just fine on some particular version of some particular compiler with some particular compiler options. Presumably it did work for the author. But you should not expect it to work consistently across compilers, or even across different versions of the same compiler.

The proper way to do this is to perform the two reads in different instructions:

GyX = (uint16_t) Wire.read() << 8;
GyX |= Wire.read();

assuming the bytes come most-significant first.

Edit: added (uint16_t) cast. C.f. this answer.

Not the answer you're looking for? Browse other questions tagged or ask your own question.