Hi everyone, costycnc here.
Have you ever written a piece of C++ code that was logically perfect, but your Arduino completely ignored it? No errors during compilation, the IDE says "Done uploading", but the hardware simply behaves as if those lines of code do not exist.
The truth is: they don't exist.
The C++ compiler is obsessed with speed and memory optimization. If it thinks a variable or an operation is useless, it brutally deletes it from the final .hex file.
To prove this to you without the usual confusing C++ abstractions, I performed a simple reverse engineering experiment using pure AVR Assembly.
The Experiment: Using NOPs as Visual Anchors
I wrote a small sketch in the Arduino IDE. I used 10 NOP (No Operation) instructions as "markers" before and after my target code. A NOP takes exactly 1 clock cycle and outputs 0x0000 in machine code, making it very easy to spot in a disassembler.
Here is the C++ code I compiled:
void setup() {
// 10 NOPs before (Visual Marker)
__asm__ __volatile__ (
"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"
"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"
);
// The target code
char ch = 'A';
__asm__ __volatile__("" :: "r" (ch)); // Force the compiler to load 'ch'
ch += 1; // Increment the character
// 10 NOPs after (Visual Marker)
__asm__ __volatile__ (
"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"
"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"
);
}
void loop() {}
The Shocking Truth Under the Hood
I took the compiled .hex file and ran it through an AVR disassembler tool to see the actual hardware instructions generated for the ATmega328P.
Here is what the CPU actually executes between our NOP markers:
; --- 11 NOPs (The compiler shifted one up for pipeline optimization) ---
NOP
NOP
...
LDI R24, 65 ; Load immediate value 65 (ASCII for 'A') into Register 24
; --- 10 NOPs after ---
NOP
NOP
...
What did the compiler do?
Looking at the disassembly, we can discover two incredible things that explain all the confusion:
- The ASCII Conversion: The letter
'A'vanished. The microcontroller only understands numbers, so the compiler immediately converted it to65and generated a singleLDI(Load Immediate) instruction. - The Disappearing Code: Where is
ch += 1;? It's completely gone. The compiler noticed that after adding 1 toch, the variable is never used again in the sketch. It decided that executing the addition was a waste of Flash memory and clock cycles, so it erased it.
Why this creates confusion (and how to fix it)
This is why Assembly is so powerful: it removes the fog of C++. If you don't know Assembly, you might spend days debugging why a manual delay loop or an interrupt variable isn't working.
If you want to stop the compiler from playing tricks on your variables, you must use the volatile keyword:
volatile char ch = 'A';
This tiny keyword tells the compiler: "Do not optimize. Do not assume. Force the hardware to write and read this value from the RAM every single time."
I hope this visual approach helps you understand what is really happening inside the silicon!
Best regards,
costycnc




