By Mohamad Wael

Last updated :

Posted :

integer literals in c

There are three kinds of integer literals in c. They are the decimal, octal and hexadecimal. The integer literals can be of the int, long, and long long type, and they can be either signed, or unsigned.

integer literals : decimal , octal , hexadecimal . int , long , long long . signed unsigned.
Table of contents Integer literals kinds Decimal integer literals: type resolution Octal and hexadecimal integer literals: type resolution Using the L and LL suffix with integer literals Using the U suffix with integer literals Mixing the U suffix with the L and LL suffixes

1- Integer literals kinds

There are three kinds of integer literals in c, they are the:

/* ********** Available integer Literals ****
        Decimal     :   starts with a non zero digit.
        octal       :   starts with 0
        hexadecimal :   starts with 0x or 0X
*  ******************************************/

#include <stdio.h>
/* include the stdio header, to use
   printf, to print formatted output .*/

#define decimalLiteral 10
// define a constant decimal integer literal 10

#define octalLiteral 010
// define an octal integer literal 10

#define hexadecimalLiteral 0x10
// define a hexadecimal integer literal 10

int main( int argc, char * argv[ ]){
    int hexLiteralCapitalX = 0X10;
    /* assign to the variable 
       hexLiteralCapitalX the 
       hexadecimal integer literal 
       10 .*/
    
    printf( "decimalLiteral is %d\n", decimalLiteral );
    //decimalLiteral is 10
    printf( "octalLiteral is %d\n", octalLiteral );
    //octalLiteral is 8
    printf( "hexadecimalLiteral is %d\n", hexadecimalLiteral );
    //hexadecimalLiteral is 16
    printf( "hexadecimalLiteral is %d\n", hexLiteralCapitalX );
    //hexadecimalLiteral is 16

    return 0;}

2- Decimal integer literals: type resolution

By default a decimal integer literal has the int type. If it is too large to fit in the int type, then it is checked against the long type. If it is too large to fit in the long type, then it is checked against the long long type. If it is still too large to fit in the long long type , then the compiler will check if it can fit in any implementation defined extended integer types, by applying the same rules described earlier, which is checking the next larger signed integer type that can hold this integer literal. If there is no type, that can hold this integer value, then it will have no type, and the result is undefined, so the compiler might throw an error.

/*
    The max integer values supported 
    on this system are:
        INT_MAX                   2147483647 
        INT_MIN                  -2147483648
        LONG_MAX         9223372036854775807 
        LONG_MIN        -9223372036854775808
        LLONG_MAX        9223372036854775807
        ULLONG_MAX      18446744073709551616 */

int main( int argc, char * argv[ ] )
{
    int anIntOne = 2147483647;
    /*  2147483647 is <= INT_MAX, as such it 
        is considered to be an int .*/

    int anIntTwo = 2147483648;
    /* compiler output:
            warning: implicit conversion 
            from 'long' to 'int'
            changes value from 2147483648 to -2147483648 .
    
        2147483648 is larger than INT_MAX, as such
        the integer literal 2147483648 is checked against 
        the next larger integer type which is long. It 
        can fit in the long type, as such it is of 
        the long type. 
        
        The declared variable anIntTwo is of the 
        int type, as such the long integer literal
        2147483648 is cast  to int, and the 
        result is -2147483648  .*/
    
    int anIntThree = 9223372036854775807;
    /*  compiler output:
            warning: implicit conversion 
            from 'long' to 'int'
            changes value from 9223372036854775807 
            to -1.
         
        The integer literal has a value 
        of 9223372036854775807 which is 
         > INT_MAX and  <= LONG_MAX, 
        as such the integer literal 
        9223372036854775807 is considered to 
        be of the long type.
        
        On this system LONG_MAX and LLONG_MAX 
        have the same max value 9223372036854775807.
        As such the integer literal
        9223372036854775807
        will never have the long long type.
        
        The declared variable anIntThree is of the
        int type, as such the long integer 
        literal 9223372036854775807 is truncated to 
        the int type, and the resulting
        value is -1 .*/

    int anIntFour = 9223372036854775808;
    /*  compiler output: 
            warning: integer literal is too
                large to be represented in type 
                'long' and is subject to 
                undefined behavior interpreting 
                as 'unsigned long'; 
        
            warning: implicit conversion from 
                'unsigned long' to
                'int' changes value 
                from 9223372036854775808 to 0 

        When the integer literal value is larger than 
        the max long long value that the system can have, 
        and when there is no extended integer type that 
        can store the integer literal value, then the 
        integer literal has no type, and the behaviour is
        undefined.
        
        On this machine, long and long long have the 
        same max limit, this is why the compiler says 
        that the integer literal cannot be stored in 
        the long type, and that the behaviour is 
        undefined. 
        
        The compiler decided to interpret the integer 
        literal as an unsigned long. Since 
        the declared  variable is of type int,  the 
        unsigned long integer literal is first 
        interpreted as a long integer literal,
        which is later on truncated to the 
        int type, and the result of the truncation 
        is 0.*/

    int anIntFive = 18446744073709551618;
    /*  compiler output 
            error: integer literal is too large to be 
            represented in any integer type
    
        When the integer literal value is larger than 
        the max long long value that the system can have, 
        and when there is no extended integral type 
        that can hold this integer literal value, the 
        behavior is undefined by the c standard.
         
        Some compilers might treat the integer literal
        as being an unsigned long long, as in the
        previous case of anIntFour, if it is 
        still larger than unsigned long long, then 
        the compiler issues an error .*/

    int anIntSix = -2147483649;
    /*  compiler output:
            warning: implicit conversion from 
            'long' to 'int' changes value from
            -2147483649 to 2147483647

        For negative values, the compiler, first 
            checks the positive value to determine 
            its data type. 
        Once the data type is determined, it performs,
            its negation to get the negative value.  
        2147483649  is larger than INT_MAX,  as such it 
            cannot be of the int type. 
        The next larger type is checked which is the 
            long type.
        2147483649 can fit in the long type, as such 
            it is of the long type. 
        The negation of 2147483649 is -2147483649.
        
        The declared variable anIntSix is of the 
         int type, as such the long integer literal
        -2147483649 is truncated to fit into int,
        and the result is 2147483647 .*/

    return 0;}

3- Octal and hexadecimal integer literals: type resolution

The octal and hexadecimal integer literals have by default the int type. If they are too large to fit in the int type, they are first checked against the unsigned int type, if they are still too large to fit in the unsigned int type, then they are checked against the long type, next against the unsigned long type, after that against the long long type, and finally against the unsigned long long type.

If the value is still too large to fit, and the compiler defines some extended integer types, then the integer literal is checked against one of these extended integer types, by applying the same rules that are described earlier, which is first trying the signed type, and next the unsigned type. If it is still too large to fit, then this integer literal has no type, and the behaviour is undefined, so the compiler might throw an error.

/*
    The max possible integer values on
    this system are:
        INT_MAX                   2147483647                     0x7fffffff
        INT_MIN                  -2147483648                    -0x80000000
        UINT_MAX                  4294967295                     0xffffffff
        LONG_MAX         9223372036854775807             0x7fffffffffffffff
        LONG_MIN        -9223372036854775808            -0x8000000000000000
        ULONG_MAX       18446744073709551616            0x10000000000000000
        LLONG_MAX        9223372036854775807             0x7fffffffffffffff
        LLONG_MIN       -9223372036854775808            -0x8000000000000000
        ULLONG_MAX      18446744073709551616            0x10000000000000000
*/

int main( int argc, char * argv[ ] ){
    unsigned int anIntOne = 0x7fffffff;
    /*  0x7fffffff is 2147483647
        2147483647 <= INT_MAX as such it
        is considered to be an int .*/

    unsigned int anIntTwo = 0xffffffff;
    /*  0xffffffff is 4294967295 ,
        INT_MAX < 4294967295 <= UINT_MAX
        so 0xffffffff is treated as an
        unsigned int .*/

    unsigned int anIntThree = 0x7fffffffffffffff;
    /*  compiler output:
            warning: implicit conversion from 'long'
            to 'unsigned int' changes value
            from 9223372036854775807 to 4294967295

        0x7fffffffffffffff is 9223372036854775807,
        UINT_MAX < 9223372036854775807 <= LONG_MAX,
        So the integer literal 0x7fffffffffffffff is
        treated as a long.
        anIntThree  is of type  unsigned int, as such 
        the long integer literal 0x7fffffffffffffff is 
        first treated as unsigned long, and next 
        truncated to unsigned int, and the result is 
        4294967295 .*/

    unsigned int anIntFour = 0x8000000000000000;
    /*  compiler output:
            warning: implicit conversion from
            'unsigned long'
            to 'unsigned int' changes
            value from
            9223372036854775808 to 0

        0x8000000000000000 is 9223372036854775808,
        LONG_MAX < 0x8000000000000000 <= ULONG_MAX
        so 0x8000000000000000 is treated as an
        unsigned long.
        anIntFour is of type unsigned int, as such
        the integer literal 0x8000000000000000 is 
        truncated to the unsigned int type and the 
        value is 0 .*/

    unsigned int anIntFive = 0x10000000000000001;
    /*  compiler output:
            error: integer literal is too large
            to be represented in any integer type

            When the value is larger than the max
            unsigned long long value that the system
            can have, and there is no extended integer
            type that can hold this value, the
            integer literal has no type, and the
            behaviour is undefined by the c standard.

            In this case the compiler raises an error.

            On this system, long and long long have the
            same max  limit .*/

    unsigned int anIntSix = -0x80000001;
    /*  -0x80000001 is equal to  -2147483649 .
        The C compiler first ignore the negative 
          sign, and check only the absolute value 
          of the integer literal to determine its type.
        After determining the data type, the compiler 
          apply the negation operator, on the absolute 
          value of the integer literal in the determined 
          data type, to calculate its negation.

        0x80000001 is larger than INT_MAX,  0x80000001 
          is a hexadecimal integer literal, as such the 
          next type to check for is, the  unsigned int 
          type.
        2147483649 is smaller than 0xffffffff, as such 
          it fits the Unsigned int type. So it is of the 
          unsigned int type.
        The negation of 2147483649 is calculated by the 
          formula -2147483649 + 2^32 = 2147483647 .

        The declared variable anIntSix is of the
          unsigned int type, as such the calculated
          value is stored in anIntSix .*/

    return 0; }

4- Using the L and LL suffix with integer literals

The letter l or L, ca be appended to an integer literal, to state that it is of the long type. The letters ll, or LL, can be appended to an integer literal, to indicate that it is of the long long type.

The same rules apply for a decimal integer literal, of the type long, or long long, as those that were described earlier in type resolution for the decimal kind, starting from long, or long long .

And the same rules apply for a hexadecimal, or an octal integer literal, of the type long, or long long, as those that were described earlier in type resolution for the hexadecimal and octal kinds, starting from long or long long.

/*
    The max possible integer value on this
    system are :
        INT_MAX                   2147483647                     0x7fffffff
        UINT_MAX                  4294967295                     0xffffffff
        LONG_MAX         9223372036854775807             0x7fffffffffffffff
        ULONG_MAX       18446744073709551616            0x10000000000000000
        LLONG_MAX        9223372036854775807             0x7fffffffffffffff
        ULLONG_MAX      18446744073709551616            0x10000000000000000


    The compiler also defines the extended integer
    type __int128 which is 128 bits long .*/

int main( int argc,  const * argv[ ] ){
    long aLongInteger = 2147483647l;
    /*  2147483647l <= INT_MAX, but
        the integer literal 2147483647l
        is of the type long since it has 
        the l suffix appended .*/

    long long aLongLongInteger = 9223372036854775807LL;
    /*  9223372036854775807LL <= LONG_MAX,  but
        the LL suffix is used, as such the integer
        literal 9223372036854775807LL is
        of the Long Long type .*/

    int anIntSix = 9223372036854775809L;
    /*
        compiler output:
            warning:
                integer constant is so large
                that it is unsigned
             warning:
                 overflow in conversion
                 from '__int128' to 'int' changes
                 value from '9223372036854775809'
                 to '1'

        9223372036854775809L > LONG_MAX , hence the
        integer literal 9223372036854775809 is matched
        against the next larger integer type.

        long long has the same max value as long, so it
        is ignored.

        The compiler defines the extended integer type
        __int128 which is 128 bit long. It can
        store the integer literal 9223372036854775809.
        As such the integer literal is treated
        as __int128.

        The declared variable anIntSix is of
        type int, as such the integer literal
        9223372036854775809 is truncated to int, 
        and the value of the truncation is 1 .*/

    return 0; }

5- Using the U suffix with integer literals

The letters u or U can be appended to an integer literal, to specify that it is of the type unsigned int. If it is too large to fit in an unsigned int, it is treated as an unsigned long, if it is still too large to fit in, it is treated as unsigned long long, if it is still too large and the compiler has an extended unsigned integer type, that can hold this integer literal, it is treated of that type, else this literal will have no type, and the behaviour is undefined .

/*
    The max possible integer values on this
    system are :
        INT_MAX                   2147483647                     0x7fffffff
        UINT_MAX                  4294967295                     0xffffffff
        LONG_MAX         9223372036854775807             0x7fffffffffffffff
        ULONG_MAX       18446744073709551616            0x10000000000000000
        LLONG_MAX        9223372036854775807             0x7fffffffffffffff
        ULLONG_MAX      18446744073709551616            0x10000000000000000
*/

int main( int argc, char * argv[ ] ){
    unsigned int anUnsingedIntOne = 2147483647u;
    /*  2147483647u<=INT_MAX, but the u
        suffix is used as such the integer
        literal is treated as an unsigned int,
        since it is less than UINT_MAX .*/

    unsigned int anUnsingedIntTwo = 9223372036854775807u;
    /*  9223372036854775807u<=LONG_MAX, but
        the u suffix is used, as such the integer
        literal is treated as an unsigned long, since
        it is less than ULONG_MAX .*/

    unsigned int anUnsingedIntThree = 18446744073709551617u;
    /*  compiler output:
            error: integer literal is too large
            to be represented in any integer

        18446744073709551617u > ULLONG_MAX, and
        there is no extended integer type, that can
        hold this integer literal value. As such this
        integer literal value has no type, and the
        behaviour is undefined by the c standard.
        The compiler raised an error .*/
    return 0;}

6- Mixing the U suffix with the L and LL suffixes

The letter u can be mixed, with both the letters L and LL, to specify that the integer literal is of type unsigned long UL, and unsigned long long ULL. The same rules apply on an unsigned long , and an unsigned long long, as those described for an unsigned int , starting unsigned long , and unsigned long long .

/*
    The max integer value on this system are :
        INT_MAX                   2147483647                     0x7fffffff
        UINT_MAX                  4294967295                     0xffffffff
        LONG_MAX         9223372036854775807             0x7fffffffffffffff
        ULONG_MAX       18446744073709551616            0x10000000000000000
        LLONG_MAX        9223372036854775807             0x7fffffffffffffff
        ULLONG_MAX      18446744073709551616            0x10000000000000000 */

int main( int argc, char * argv[ ] ){
    unsigned long unsignedLongInteger = 2147483647ul;
    /*  2147483647ul < INT_MAX, but the ul
        suffix is used, as such the integer literal
        2147483647 is treated as an unsigned long,
        since it is less than ULONG_MAX .*/

    unsigned long long unsignedLongLongInteger = 9223372036854775807LLU;
    /*  9223372036854775807LLU  <= LONG_MAX, but the
        llu suffix is used, as such the integer literal
        9223372036854775807 is treated as an
        unsigned long long, since it is less than
        ULLONG_MAX .*/

    unsigned long long unsignedLongLongIntegerError = 18446744073709551616LLu;
    /*
        compiler output:
            error: integer literal is too large to be
            represented in any integer type

        18446744073709551616LLu > ULLONG_MAX,
        the compiler does not define extended integer
        types, as such the integer literal has no type,
        and the behaviour is undefined. The compiler
        raised an error .*/

    return 0;}