It depends on what integer type is selected by the compiler to be compatible with the enumeration type. The compiler can select an unsigned integer type.
In this statement
printf("now a is %d\n", a);
you are using the conversion specifier %d designed for signed integer types though the enumeration can be compatible with an unsigned integer type and if you will use the conversion specifier %u you will get another result.
If for example you will declare an enumeration constant as having a negative value then the compiler will select a signed integer type as compatible with the enumeration.
Here are two demonstrative programs that show the difference
#include <stdio.h>
int main( void )
{
enum Direction {N,W,S,E};
enum Direction a = N;
--a;
printf( "a < 0 is %d\n", a < 0 );
}
The output of this program is
a < 0 is 0
The compiler selected an unsigned integer type as the compatible integer type.
#include <stdio.h>
int main( void )
{
enum Direction {N = -1, W,S,E};
enum Direction a = W; // W is equal to 0
--a;
printf( "a < 0 is %d\n", a < 0 );
}
The output of this program is
a < 0 is 1
because the compiler selected a signed integer type as the compatible integer type.
Form the C Standard (6.7.2.2 Enumeration specifiers)
4 Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined,128) but shall be capable of representing the
values of all the members of the enumeration. T
That is there is a difference between an enumeration type and an enumeration constant. Enumeration constants always have the type int. But enumeration types are compatible with integer types (signed or unsigned) selected by the compiler.
Compare the two calls of printf in this demonstration program.
#include <stdio.h>
int main( void )
{
enum Direction {N,W,S,E};
enum Direction a = N;
printf( "a - 1 < 0 is %d\n", a - 1 < 0 );
printf( "N - 1 < 0 is %d\n", N - 1 < 0 );
}
where the program output is
a - 1 < 0 is 0
N - 1 < 0 is 1