5

I saw in /usr/include/limits.h as

/* Minimum and maximum values a `signed long int' can hold.  */
if __WORDSIZE == 64
 define LONG_MAX     9223372036854775807L
else
 define LONG_MAX     2147483647L
endif
define LONG_MIN      (-LONG_MAX - 1L)
/* Maximum value an `unsigned long int' can hold.  (Minimum is 0.)  */
if __WORDSIZE == 64
 define ULONG_MAX    18446744073709551615UL
else
 define ULONG_MAX    4294967295UL
endif
ifdef __USE_ISOC99

/* Minimum and maximum values a `signed long long int' can hold.  */
define LLONG_MAX    9223372036854775807LL
define LLONG_MIN    (-LLONG_MAX - 1LL)

/* Maximum value an `unsigned long long int' can hold.  (Minimum is 0.)    */
 define ULLONG_MAX   18446744073709551615ULL

So unsigned long long int and unsigned long int seem to have same max value of 18446744073709551615 ...

Does that mean long long means same as long in this machine? If so, why then do we have a separate long long specifier?

From reading C books, I expected long long to be double the size of long. Am I going wrong somewhere? (But yes, I agree with standards that int >= short int, long >= int, but it is hard to digest long long >= long.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Harish Kayarohanam
  • 3,886
  • 4
  • 31
  • 55
  • 5
    "so does that mean long long means same as long in this machine . so why then do we have a separate long long specifier ?" Mmmmh because your machine is not the only machine on the earth ? – mathieu Apr 12 '15 at 18:29
  • hmm .. I think it will be the same across all linux 64 bit machines(may be different in windows) ... check yours too ? – Harish Kayarohanam Apr 12 '15 at 18:29
  • 1
    See [What is the bit size of `long` on 64-bit Windows?](http://stackoverflow.com/questions/384502/what-is-the-bit-size-of-long-on-64-bit-windows) On such machines, `long long` is bigger than `long`. On your machine, the two types are the same size. Both are completely valid — get used to it. – Jonathan Leffler Apr 12 '15 at 18:50
  • "I think it will be the same across all linux 64 bit machines" -- although this may happen to be true for all currently available C implementations for 64-bit Linux, I cannot confirm that, and it is not safe to assume that is so. If it were so, it would not be safe to assume that it will remain so. – John Bollinger Apr 12 '15 at 18:54
  • 1
    It would be possible to design and build a compiler that supported `CHAR_BIT == 8`, `sizeof(short) == 2`, `sizeof(int) == 4`, `sizeof(long) = 8`, `sizeof(long long) == 16` (aka 128 bits) and `sizeof(intmax_t) == 32` (aka 256 bits). After that, you run out of standard names for different size integers apart from using the numeric `int64_t`-style names. – Jonathan Leffler Apr 12 '15 at 19:37
  • The only thing really certain is the sizeof( long long ) >= sizeof( long ) >= sizeof( int ) >= sizeof( short ) >= sizeof( char ). See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf, which is the C standard. – Andrew Henle Apr 12 '15 at 20:02
  • Given 5 `char, short, int, long, long long` and 4 common widths of 8,16, 32, 64, there is one extra type. Having a redundant type somewhere is certainly less work for a complier implementor. I suspect `long long` as `int128_t` will come along when there is enough user need/demand for it. My crystal ball says 2020. – chux - Reinstate Monica Apr 13 '15 at 03:38

3 Answers3

6

The C language specification specifies types that conforming implementations must provide. Type long [int] has been among them since the first version of the standard, and type long long [int] has been among them since C99.

The standard specifies relationships among the sizes of the various integer types, and in particular that type long long must be able to represent all the values that type long can represent, but it leaves many aspects of type characteristics "implementation defined", meaning implementations choose (and are obligated to document their choice). Among those characteristics are whether there are any long long values that are outside the range of long.

At the level of the standard, none of that is directly related to the native word size of the implementation's target machine, but implementations are free to use that as a criterion when they choose type representations.

If you care about the range of values that various types you use can represent, then use the fixed-width types from stdint.h (int64_t, uint32_t, etc.), or use the standard macros giving the integer type limits, (INT_MAX and friends).

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
4

C has two kinds of integral types :

  • traditionals : short, int, long, long long. It is up to each implementation to define what size those types are. C just specifies that sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) (ref 6.3.1.1 in final draft of C1X). With those types you can never be sure which one is 32 or 64 bits long because it is explicitly implementation dependent
  • explicits : int8_t, int16_t, int32_t, int64_t - when they exist you can be sure of their size. Standard say they should be declared in stdint.h, but unfortunately, they are all optional - that means you cannot be sure they exist even if all major implementation support int16_t, int32_t and int64_t (ref : 7.20 and 7.20.1.1 of above draft)

And ... there is no recommended relation between traditionals and explicits types (note the appellations traditionals and explicits are mine).

7.20.1 of same draft defines other interesting types :

  • intptr_t and uintptr_t : resp. signed and unsigned integral types guaranteed to be large enough to hold a pointer (unluckily, those types are optionals ...)
  • int_leastX_t : a type of at least X bits
  • int_fastX_t : the fastest type of at least X bits

The following types are required (meaning they shall exist in any conformant implementation) :

int_least8_t int_least16_t int_least32_t int_least64_t uint_least8_t uint_least16_t uint_least32_t uint_least64_t

int_fast8_t int_fast16_t int_fast32_t int_fast64_t uint_fast8_t uint_fast16_t uint_fast32_t uint_fast64_t

  • intmax_t and uintmax_t : signed (resp unsigned) integer type capable of representing any value of any signed (resp unsigned) integer type - required
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • No mention of the 'least' or 'fast' explicit types? – Jonathan Leffler Apr 12 '15 at 19:05
  • @JonathanLeffler : it was not explicitely required by OP, but I must admit the answer is now more complete – Serge Ballesta Apr 12 '15 at 19:23
  • Sadly, by covering the extra types, it cannot be as succinct as it was without mentioning them (you're covering twice as many types as before), but (as you note) the 'least' and 'fast' types are reliably present (unlike the exact types) and therefore have value. – Jonathan Leffler Apr 12 '15 at 19:30
3

You asked:

so does that mean long long means same as long in this machine

The type names are different even when they are of the same size.

so why then do we have a separate long long specifier ? `

The language specifies them as different types. It's up to a platform what size of integral number to use to support them. In the compiler you are using long long and long have the same size. It's possible for a different compiler on the same platform to use 64 bits for long long and 32 bits for long and int.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • ya .. but here so the long long is not useful here ? – Harish Kayarohanam Apr 12 '15 at 18:31
  • ok .. my doubt then ... if systems are so different in the bit sizes may be 64 bit and 32 bit and may be windows and linux .. is it not hard to write software that works everywhere ? – Harish Kayarohanam Apr 12 '15 at 18:32
  • 1
    @HarishKayarohanam, if you are writing a program explicitly for this platform, then using `long long` does not give you any any advantage. If you are interested in writing a program that is portable to another platform where using maximum size of `long long` will be an advantage, then you `long long`. – R Sahu Apr 12 '15 at 18:35
  • @HarishKayarohanam, you are converting this into a chat :) – R Sahu Apr 12 '15 at 18:35