I have this long array of 64 values going from 0 to 15, values which only cost 8 bits, for a pulse width modulation.

So I made a test to see its cost in space, commenting one of the two arrays.

const byte wave[64] = {8,9,9,10,11,11,12,12,13,13,14,14,14,15,15,15,15,15,15,15,14,14,14,13,13,12,12,11,11,10,9,9,8,7,7,6,5,5,4,4,3,3,2,2,2,1,1,1,1,1,1,1,2,2,2,3,3,4,4,5,5,6,7,7};
//const byte wave[2] = {8,9};
byte i = 0;
void setup() {pinMode(1,OUTPUT);}
void loop() {            //(Don't worry about the code in here, 
  analogWrite(1,wave[i]);//it's just to get the program 
  i++;delay(1);          //to hold on to the data)

The compiler said Sketch uses 1112 and 1050 bytes (3%) of program storage space. or a difference of 62 bytes.

This tells me that one could save a lot of memory by keeping them in a 4-bit or what I'd like to call half byte, going from 0 to f rather than from 00 to ff.

How could I do so without turning the code to unreadable bit mush?

  • 2
    You can always use Nibbles. Just store on number in the first half of a byte and the other in the second half. to read it back, just shift and AND it with an appropriate mask.
    – Kwasmich
    Commented Jul 13, 2020 at 6:29
  • 1
    You could definitely stuff 64 of your 4-bit integers into a byte array with 32 slots, but if your plan is to specify the contents of that byte array as you have in your sample code, then it might not help much. If, on the other hand, you were reading your array of 4-bit integers from somewhere else (e.g., from flash memory or from a UART input) then you might be in luck. In declaring const byte wave[64] you've told your program to allocate 64 bytes and the ship has sailed.
    – S. Imp
    Commented Jul 13, 2020 at 6:42
  • 1
    If the compiler get's it right, it is just ONE additional instruction (AND) to read the right Nibble and TWO instructions (SWAP + AND) to read the left Nibble. So it takes 6 bytes more for your code, but on the other hand you save 32 bytes on your data.
    – Kwasmich
    Commented Jul 13, 2020 at 6:43
  • 1
    Are you sure you don't have enough memory? How likely is it? Are you going to manufacture tens of thousands of it, or could you just buy a chip with more memory? Otherwise I'd say that's premature optimization. Commented Jul 13, 2020 at 7:59
  • 1
    the data looks like a sine wave lookup table ... you only need to store a 1/4 wave
    – jsotola
    Commented Jul 13, 2020 at 8:08

2 Answers 2


Keeping your 4-bit values in half-bytes is doable using structs and bitfields. You'll want an access function to separate the "array index" into a byte-index and a nibble selector (the LSb of the "array index") and return or store the appropriate nibble.

This related question on StackOverflow has some answers showing ways to do this. There will be obviously be some overhead to unpacking 4-bit nibbles since they can't be addressed directly, but it will be minor and is the trade-off for saving memory when memory is scarce.


If the point is to save program storage space, you're probably going to have to live with some unreadable bit mush or do bit-swapping in your head. Here's a code example that encodes your same array as a 32-byte array, but you have to combine pairs of your original numbers into bytes. It's not especially difficult because each hex digit represents one of your original numbers.

I.e., 8,9 becomes 0x89. Likewise, A is 10, B is 11, etc. Then you can iterate 1 thru 64 and do some division and bit-shifting to pull out the original value you wanted. This will iterate through your 32-byte array and pull out 64 half-byte values.

    const byte wave[32] = {0x89,0x9A,0xBB,0xCC,0xDD,0xEE,0xEF,0xFF,0xFF,0xFF,0xEE,0xED,0xDC,0xCB,0xBA,0x99,0x87,0x76,0x55,0x44,0x33,0x22,0x21,0x11,0x11,0x11,0x22,0x23,0x34,0x45,0x56,0x77};
    for(int i=0; i<64; i++) {
        byte val;
        if (i % 2) {
            // the little byte is first (LITTLE ENDIAN)
            val = wave[i/2] & 0x0F;
        } else {
            // the BIG byte is second
            val = (wave[i/2] >> 4) & 0x0F;
        Serial.printf("%i=%i\n", i, val);

NOTE: that the Endianness if your system may be different than mine. Most systems are little-endian these days, but you never know.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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