Understanding -fshort-enums
in C
When working with enumerations (enum
) in C, it’s easy to assume they are always 4 bytes, just like int
. However, compilers offer optimization flags like -fshort-enums
that can reduce memory usage by adjusting enum sizes based on the range of their values.
In this post, we’ll explore how -fshort-enums
affects enum size, element size, and variable size through explanation and example.
🔍 What Does -fshort-enums
Do?
By default, the C compiler treats all enum types as int
, which typically means 4 bytes of memory regardless of the values they store. The GCC flag -fshort-enums
changes this behavior:
With
-fshort-enums
, the compiler chooses the smallest integer type (starting from 1 byte) that can represent all the enum values.
📐 Explanation with -fshort-enums
- Enum Type Size: The size of the enum type itself is minimized.
- For
Enum_8bit
, values range from 1–4 → 1 byte. - For
Enum_16bit
, values are within 16-bit range → 2 bytes.
- For
-
Enum Element Size: Each enum element like
CAN1
,IP4
, orVP3
is treated as anint
, which is 4 bytes, unless the value itself demands a larger type (e.g., 64-bit values). - Enum Variable Size: The actual variable holding the enum takes up memory based on the enum’s underlying type (1, 2, or 4 bytes), not necessarily the element size.
🧪 Code Example: Exploring Enum Sizes
#include<stdio.h>
typedef enum {
CAN1 = 1,
CAN2,
CAN3,
CAN4,
} Enum_8bit;
typedef enum {
IP4 = 0x1234,
IP5 = 0x444,
IP6 = 0xffee,
} Enum_16bit;
typedef enum {
VP1 = 0x1234,
VP2 = 0x444,
VP3 = 0xffeeEEEEEEEEEDDE,
} Enum_32bit;
void main(void) {
printf("Enum_8bit is %lu.\n", sizeof(Enum_8bit));
printf("Enum_16bit is %lu.\n", sizeof(Enum_16bit));
printf("Enum_8bit element is %lu.\n", sizeof(CAN1));
printf("Enum_16bit element is %lu.\n", sizeof(IP4));
printf("Enum_32bit 64bits element is %lu.\n", sizeof(VP3));
printf("Enum_32bit 16bits element is %lu.\n", sizeof(VP2));
Enum_16bit bit16 = IP4;
Enum_8bit bit8 = CAN1;
printf("Enum_8bit variable is %lu.\n", sizeof(bit8));
printf("Enum_16bit variable is %lu.\n", sizeof(bit16));
}
🛠 Compilation Results
✅ With -fshort-enums
:
Enum_8bit is 1.
Enum_16bit is 2.
Enum_8bit element is 4.
Enum_16bit element is 4.
Enum_32bit 64bits element is 8.
Enum_32bit 16bits element is 4.
Enum_8bit variable is 1.
Enum_16bit variable is 2.
🚫 Without -fshort-enums
:
Enum_8bit is 4.
Enum_16bit is 4.
Enum_8bit element is 4.
Enum_16bit element is 4.
Enum_32bit 64bits element is 8.
Enum_32bit 16bits element is 4.
Enum_8bit variable is 4.
Enum_16bit variable is 4.
📌 Summary
- ✅ Default Behavior: Without any flags, enums default to 4 bytes (
int
) for all values. - ✅ Optimized with
-fshort-enums
:- Enum types are downsized to the smallest suitable integer type.
- Enum elements still behave like
int
unless the value dictates otherwise. - Enum variables take on the type size defined by the enum type, making the optimization effective for memory footprint.
- ⚠️ Memory Alignment: Be aware that actual size might still vary based on your platform’s architecture and data alignment rules.
💡 Why This Matters
Using -fshort-enums
can significantly reduce memory usage in embedded systems, low-level drivers, or applications where space efficiency is critical. However, it may also introduce portability concerns if not carefully managed across different compilers or platforms.