Search code examples
cenumscomparisonimplicit-conversionenumerator

Output of -1L < 1U and -1L > UL is different when -1L, 1U and -1UL are symbolic constant than when they are declared as enum constant


B&R say in their book "The C Programming Language"- Enumerations provide a convenient way to associate constant values with names, an alternative to #define with the advantage that the values can be generated for you.

So I defined enum constants for -1L, 1U and 1UL. The result is not what I expected, it should have been the same in both cases.

#include<stdio.h>

#define NEGATIVE_SIG_LONG -1L
#define UNSIG_INT 1U
#define UNSIG_LONG 1UL

main()
{
  enum { ENUM_NEGATIVE_SIG_LONG = -1L, ENUM_UNSIG_INT = 1U, ENUM_UNSIG_LONG = 1UL};                                                                                                                                 

  printf("-1L < 1U: %d\n", -1L < 1U); // outputs: 1
  printf("-1L > 1UL: %d\n\n", -1L > 1UL); // outputs: 1

  printf("-1L < 1U: %d\n", NEGATIVE_SIG_LONG < UNSIG_INT); // outputs: 1
  printf("-1L > 1UL: %d\n\n", NEGATIVE_SIG_LONG > UNSIG_LONG); // outputs: 1

  printf("-1L < 1U: %d\n", ENUM_NEGATIVE_SIG_LONG < ENUM_UNSIG_INT); // outputs: 1
  printf("-1L > 1UL: %d\n", ENUM_NEGATIVE_SIG_LONG > ENUM_UNSIG_LONG); // outputs: 0, expected 1

  return 0;
}

Solution

  • In C enumeration constants have the type int.

    From the C Standard (6.4.4.3 Enumeration constants)

    2 An identifier declared as an enumeration constant has type int

    So in this call

    printf("-1L < 1U: %d\n", ENUM_NEGATIVE_SIG_LONG < ENUM_UNSIG_INT); // outputs: 1
    

    there is used the expression

    -1 < 1
    

    that yields to 1.

    In this call

    printf("-1L > 1UL: %d\n", ENUM_NEGATIVE_SIG_LONG > ENUM_UNSIG_LONG); // outputs: 0, expected 1
    

    there is used the expression

    -1 > 1
    

    that yields 0.

    As for these calls

    printf("-1L < 1U: %d\n", -1L < 1U); // outputs: 1
    printf("-1L > 1UL: %d\n\n", -1L > 1UL); // outputs: 1
    

    then it seems the type signed long can contain all values of the type unsigned int. So the expression

    -1L < 1U
    

    yields 1.

    On the other hand, the type signed long is unable to contain all values of the type unsigned long. The common type will be unsigned long. So the expression -1L is converted to the type unsigned long and yields the maximum value of this type that is greater than 1UL.

    Pay attention to that the function main shall have the return type int.

    int main( void )