By 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 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 const *argv[])
{
    int hexadecimalLiteralWithX = 0X10;
    // assign to the variable 
    // hexadecimalLiteralWithX 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", hexadecimalLiteralWithX);
    //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 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 const *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 cast 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 cast to the 
        int type , and the result of the conversion 
        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 
        behaviour 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 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 const *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 cast to an 
        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 cast 
        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 th 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 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, char const *argv[])
{
    long aLongInteger = 2147483647l;
    /*
        2147483647l <= INT_MAX , but 
        the integer literal 2147483647l , 
        is of 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 cast to int , and the 
        value of the casting is 1 . 
    */
 
    return 0;
}

5- Using the U suffix with integer literals

The letter 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 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 const *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 for 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 const *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;
}