To try to get some substantial elements to the answer, I made a simple test.
Code
I wrote a simple C program main.c:
#include <stdio.h>
#include "constants.h"
// Define states
#define STATE_STANDBY 0
#define STATE_START 1
#define STATE_RUN 2
#define STATE_STOP 3
// Common code
void wait(unsigned int n)
{
unsigned long int vLoop;
for ( vLoop=0 ; vLoop<n*LOOP_SIZE ; ++vLoop )
{
if ( (vLoop % LOOP_SIZE) == 0 ) printf(".");
}
printf("\n");
}
int main ( int argc, char *argv[] )
{
int state = 0;
int loop_state;
for ( loop_state=0 ; loop_state<MACHINE_LOOP ; ++loop_state)
{
if ( state == STATE_STANDBY )
{
printf("STANDBY ");
wait(10);
state = STATE_START;
}
else if ( state == STATE_START )
{
printf("START ");
wait(20);
state = STATE_RUN;
}
else if ( state == STATE_RUN )
{
printf("RUN ");
wait(30);
state = STATE_STOP;
}
else // ( state == STATE_STOP )
{
printf("STOP ");
wait(20);
state = STATE_STANDBY;
}
}
return 0;
}
while constants.h contains
#define LOOP_SIZE 10000000
#define MACHINE_LOOP 100
And I considered three variants to define the state constants. The macro as above, the enum:
enum {
STATE_STANDBY=0,
STATE_START,
STATE_RUN,
STATE_STOP
} possible_states;
and the const
:
static const int STATE_STANDBY = 0;
static const int STATE_START = 1;
static const int STATE_RUN = 2;
static const int STATE_STOP = 3;
while the rest of the code was kept identical.
Tests and Results
Tests were made on a 64 bits linux machine and compiled with gcc
Global Size
gcc main.c -o main
gives
macro: 7310 bytes
enum: 7349 bytes
const: 7501 bytes
gcc -O2 main.c -o main
gives
macro: 7262 bytes
enum: 7301 bytes
const: 7262 bytes
gcc -Os main.c -o main
gives
macro: 7198 bytes
enum: 7237 bytes
const: 7198 bytes
When optimization is turned on, both the const and the macro variants come to the same size. The enum is always slightly larger. Using gcc -S
I can see that the difference is a possible_states,4,4
in .comm. So the enum is always larger than the macro. and the const can be larger but can also be optimized away.
Section size
I checked a few sections of the programs using objdump -h main
: .text, .data, .rodata, .bss, .dynamic. In all cases, .bss has 8 bytes, .data, 16 bytes and .dynamic: 480 bytes.
.rodata has 31 bytes, except for the non-optimized const version (47 bytes).
.text goes from 620 bytes up to 780 bytes, depending on the optimisation. The const unoptimised being the only one differing with the same flag.
Execution speed
I ran the program a few times, but I did not notice a substantial difference between the different versions. Without optimisation, it ran for about 50 seconds. Down to 20 seconds with -O2
and up to more than 3 minutes with -Os
. I measured the time with /usr/bin/time
.
RAM usage
Using time -f %M
, I get about 450k in each case, and when using valgrind --tool=massif --pages-as-heap=yes
I get 6242304 in all cases.
Conclusion
Whenever some optimisation has been activated, the only notable difference is about 40 Bytes more for the enum case. But no RAM or speed difference.
Remains other arguments about scope, readability... personal preferences.