Understanding Program Size - ATMega328P

I am interested in finding out the memory usage of my code running on an ATMega328P (16 MHz) using the avr-size utility bundled with WinAVR 20100110. Using the Makefile included in the distribution I obtained the following memory usage for the code below:

Here is the date sheet of atmega328p

#include <avr/io.h>
#include <stdint.h>

int main(void)
{
while(1)
{ }
return 0;
}

The console output is:

make all

———— begin ————
avr-gcc (WinAVR 20100110) 4.3.3
Copyright © 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Compiling C: src/main.c
avr-gcc -c -mmcu=atmega328p -I. -gdwarf-2 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=./src/main.lst -std=gnu99 -MMD -MP -MF .dep/main.o.d src/main.c -o src/main.o

Linking: src/main.elf
avr-gcc -mmcu=atmega328p -I. -gdwarf-2 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=src/main.o -std=gnu99 -MMD -MP -MF .dep/main.elf.d src/main.o —output src/main.elf -Wl,-Map=./src/main.map,—cref -lm

Creating load file for Flash: src/main.hex
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature src/main.elf src/main.hex

Creating load file for EEPROM: src/main.eep
avr-objcopy -j .eeprom —set-section-flags=.eeprom=“alloc,load” \
—change-section-lma .eeprom=0 —no-change-warnings -O ihex src/main.elf src/main.eep || exit 0

Creating Extended Listing: src/main.lss
avr-objdump -h -S -z src/main.elf > src/main.lss

Creating Symbol Table: src/main.sym
avr-nm -n src/main.elf > src/main.sym

Size after:
AVR Memory Usage
————————
Device: atmega328p

Program: 134 bytes (0.4% Full)
(.text + .data + .bootloader)

Data: 0 bytes (0.0% Full)
(.data + .bss + .noinit)

———— end ————

When I run the same code with the while() construct removed the program size is reported to be 138 bytes. Same happens if I comment out both while() and the return statement. How can the program size increase when I remove a loop construct? The Makefile uses the -S optimizer for gcc. Does it have something to do with it?

Most likely the code for exiting the main function (whatever that means in a flashlight) takes more space than the code for the empty loop. In a PC returning from a function, if not inlined, usually means putting the result in the stack or in a register and restoring the instruction pointer.

As the loop is infinite, the compiler can detect that the return is never reached (dead code), so it would remove the instructions for it. The only way to know for sure what the compiler is doing, would be using some kind of dissasembler to check the program.

My advice is… don’t care about it. I’ve given up trying to understand what happens behind the scenes when C/C code is translated, especially when it comes to size.

Size of code will to a very large degree depend on used libraries.
I.e. everything you use something new a extra library may be included. Like first float or string operation will include the library for that, next time you use the same function again the library is already included and only the actual code generated for that statement will count.

Nothing in the while() loop ever returns 0, therefore the while() loop is infinite and all code after the loop is deemed unreachable by the optimizer and dropped. As mentioned, it’s only 4 bytes on a device with 16kb Flash so not sure the issue.

There's no point in even questioning this for any real practical purpose? Optimized compilers are pretty sophisticated now. Since when you remove the while loop, effectively you have no code defined, so it might be putting in some stub code. The 4 bytes is way too small to be concerned about.

I've spent time optimizing code with the ATtiny85, and get no gain whatsoever - the optimizers sometimes already optimize out duplicate code. They are seeing the same thing I am.