# Set and extract individual bytes of a number (lowByte() and highByte())

You can extract

the low-order (rightmost) byte of a variable

or

the high-order (leftmost) byte of a word

with the functions `lowByte()` and `highByte()` respectively (the quotes are from the Arduino Reference).

Does Arduino provide a way to extract any byte from a number with a similar function?

And does it provide a way to set any individual bytes of a number (which would be the counterparts to these functions, if they exist)?

Any more sophisticated byte exchange can be done with binary operators.

## Extracting information

You'll need some constants like

``````MASK         SHIFT
0xFF000000   24       (first byte, most significant)
0x00FF0000   16       (second byte)
0x0000FF00    8       (third byte)
0x000000FF    0       (last byte, least significant)
``````

You would binary AND the original value with MASK

``````     0x12345678
AND  0x00FF0000
=   0x00340000
``````

and then bit shift it left, e.g.

``````   0x00340000
>> 16
= 0x00000034
``````

So from the original value 0x12345678 you have gotten 0x34.

## Setting information

The opposite direction is also possible with the same constants but opposite operators and in opposite order:

``````   0x00000034
<< 16
= 0x00340000
``````

and then

``````   0x12005678
OR 0x00340000
= 0x12345678
``````

Note that the OR operation only works reliably if the corresponding positions are 0x00. That's fine with a starting value of 0x00000000.

If you don't know that or you want to process an arbitrary number, you can introduce a step in between

``````    0x12??5678   (?? could be anything)
AND 0xFF00FFFF   (which is the inverse of 0x00FF0000 and can be expressed as ~0x00FF0000)
=  0x12005678   (whatever ?? was, it'll be cleared out)
``````

## Actual Code

Tested on Arduino Uno. The `long` data type is 32 bits or 4 bytes.

The code here may not be the most efficient. Advanced developers would likely not use `MASK` and `SHIFT` as arrays like this. This answer focuses more on the educational point.

``````long MASK[]  = {0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF};
byte SHIFT[] = {24        , 16        , 8         , 0};

// Extracts a byte from a larger data type
// value: larger data type to extract a byte from
// position: 0 based number, 0 = MSB, 3 = LSB
byte getByteAt(long value, byte position)
{
long result = value & MASK[position];  // binary AND
result = result >> SHIFT[position];    // Shift right, moving all bits
byte resultAsByte = (byte) result;     // Convert to an actual byte
return resultAsByte;
}

// Sets a byte in a larger data type
// value: larger data type where to set the byte
// position: 0 based number, 0 = MSB, 3 = LSB
// newPartialValue: the byte to be inserted
long setByteAt(long value, byte position, byte newPartialValue)
{
long result = value & ~MASK[position];                       // clear the affected byte so that it is 0x00
long valueToSet = (long) newPartialValue << SHIFT[position]; // Shift left, moving all bits
result = result | valueToSet;                                // binary OR
return result;
}

void setup() {
Serial.begin(9600);
Serial.println(getByteAt(0x12345678, 1));       // Prints 52, which is 0x34
Serial.println(setByteAt(0x87654321, 1, 0xBB)); // Prints -2017770719 which is 0x87BB4321
}

void loop() {

}
``````
• Worth mentioning that the value you `AND` the number with to clear the bits prior to `OR`-ing is the inverse of the mask. You can use `~MASK` to create it. – Majenko Nov 28 '19 at 11:32
• @Majenko: used and added in the example – Thomas Weller Nov 28 '19 at 11:50
• Thanks for the extensive explanation, but I already knew about this possibility. So there is no inherent way to do this with built in functions? – LukasFun Nov 28 '19 at 12:04
• You don't need to load MASK and SHIFT from an array! shift = `position * 8 = position << 3` (convert a bit offset to a byte offset. Also, mask after shifting so it's just `return (uint8_t)(value >> shift);`. e.g. on Godbolt for AVR and ARM cortex-M0 get and set byte functions: godbolt.org/z/2uFXN5 Also included are versions that store/reload and use a byte index, avoiding shift loops on AVR which can only shift 1 byte at a time. (Will post an answer if I get back to this.) – Peter Cordes Nov 28 '19 at 23:17
• @PeterCordes: my primary concern was to explain it thoroughly and in an understandable, visible way. I am also participating in code golf, so yeah, it's definitely not the shortest form :-) In general I am not optimizing for speed as long as there is no speed requirement. – Thomas Weller Nov 28 '19 at 23:53

The header Arduino.h defines the macro `word(high_byte, low_byte)`. The resulting value is an `uint16_t`.

• Thank you, that answers the question about the counterpart of `lowByte()` and `highByte()`. Are there any functions for the rest of my question though? – LukasFun Nov 28 '19 at 15:38
• @LukasFun: I couldn't find any. But note that on the AVR-based Arduinos an `int` is only two bytes. – Edgar Bonet Nov 28 '19 at 15:58
• You should simply treat those definitions as samples, learn enough C/C++ to understand them, and extend them to whatever you need. If uint16_t is not what you need, why should exactly uint32_t be your solution? – DataFiddler Nov 28 '19 at 16:11

There are two alternative methods, and they can both be easily used "in reverse" as well:

### Unions

``````union byte_extract {
uint32_t ival;
struct {
uint8_t byte_0; // least significant byte
uint8_t byte_1;
uint8_t byte_2;
uint8_t byte_3; // most significant byte
} bval;
};

... later ...

union byte_extract x;

x.ival = 65536 * 99; // change to whatever you want
Serial.println(x.bval.byte_2); //3rd byte
``````

Unions are a way to define multiple possible ways to interpret a piece of memory, usually to save memory when you know something can't be 2 things at once. Strictly speaking it is not recommended to use them in this way but it works.

### Pointer arithmetic

``````uint32_t *xaddr;

uint32_t x = 65536 * 99; // change to whatever you want

``````

Memory addresses (on Arduino as well as on PCs) refer to the first byte of a variable. If you have an (uint32_t *) you will read 4 bytes starting at that address. But if you have a (uint8_t *) or a (char *) you will only read 1 byte. You can shift this pointer-to-uint8_t forwards by as many bytes as you want.

Apologies if this doesn't quite work on Arduino, I have only tested it on PC.

• This use of unions is well-defined by C99. An array of `uint8_t bytes[4]` would be more readable and allow runtime indexing, though. Your pointer-arithmetic version is only safe because `uint8_t` is going to be `unsigned char`, and `unsigned char*` is allowed to alias anything without violating strict-aliasing. Note that both of these are endianness-dependent. – Peter Cordes Dec 11 '19 at 0:18