What does this notation stands for? Wire.read() <<8 | Wire.read()
Just adding a couple of points to Michel Keijzers's answer.

The expression Wire.read() &lt;&lt; 8 takes the value returned by
Wire.read(), which is an int, and shifts it 8 bits to the left,
which is equivalent to multiplying by 256. If you are using a 32-bit
microcontroller (e.g. an Arduino Due), this is safe. However, most
Arduinos are based on an 8-bit AVR chip. On them, an int is 16-bits
and can only hold values up to 32767. If the initial value is larger
than 127, then the bit shift causes a signed integer overflow, which in
C and C++ is undefined behavior (read: “illegal operation”). It is
likely that everything runs fine and you get the expected result, but
it is unwise to ever rely on undefined behavior in C or C++.

The proper way to do the shift is to cast the initial value to an
unsigned data type, which is always safe v.s. overflows, and then do the
shift, like in



((uint16_t) Wire.read()) &lt;&lt; 8


You may omit the outer parentheses if you know your operator priorities.

The second point is about the already mentioned fact that the order of
the reads is not specified. The simplest fix is to do one read per
statement, as in:

AcX = (uint16_t) Wire.read() &lt;&lt; 8;  // first read MSB
AcX |= Wire.read();                 // then LSB


It is worth noting that the first statement has an implicit cast from
uint16_t (the result of the shift) to int16_t (the type of AcX).
This can also overflow if the shifted value is larger than 32767.
However, an overflow happening during a conversion in not undefined,
but rather implementation defined behavior. This means that the
authors of the compiler must decide and document what happens. Arduino
code is usually compiled by gcc, and the gcc docs document this
behavior as


  • The result of, or the signal raised by, converting an integer to a
  signed integer type when the value cannot be represented in an object
  of that type (C90 6.2.1.2, C99 and C11 6.3.1.3).
  
  For conversion to a type of width N, the value is reduced modulo 2^N
  to be within range of the type; no signal is raised.


This is exactly what we want here, and since it is the most efficient
choice on a two’s complement architecture, it seems unlikely that
another compiler would make a different choice.