89

I am trying this code on GNU's C++ compiler and am unable to understand its behaviour:

#include <stdio.h>;

int main()
{
    int  num1 = 1000000000;
    long num2 = 1000000000;
    long long num3;
    //num3 = 100000000000;
    long long num4 = ~0;

    printf("%u %u %u", sizeof(num1), sizeof(num2), sizeof(num3));
    printf("%d %ld %lld %llu", num1, num2, num3, num4);
    return 0;
}

When I uncomment the commented line, the code doesn't compile and is giving an error:

error: integer constant is too large for long type

But, if the code is compiled as it is and is executed, it produces values much larger than 10000000000.

Why?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sud03r
  • 19,109
  • 16
  • 77
  • 96
  • 9
    May be too late now but for future readers, I suggest you use `` and use `uint64_t`. To display a 64 bit value, `printf( "%" PRIu64 "\n", val);` – enthusiasticgeek Aug 13 '12 at 15:36
  • @enthusiasticgeek `` included, `uint64_t a = 0xffffffffffffff; printf( "%" PRIu64 "\n",a ); : error: expected ‘)’ before ‘PRIu64’ printf( "%" PRIu64 "\n",a ); :: warning: spurious trailing ‘%’ in format [-Wformat=] printf( "%" PRIu64 "\n",a );` – Herdsman May 09 '20 at 22:03
  • `#define __STDC_FORMAT_MACROS 1` See https://stackoverflow.com/questions/14535556/why-doesnt-priu64-work-in-this-code – enthusiasticgeek Dec 07 '20 at 16:58

5 Answers5

155

The letters 100000000000 make up a literal integer constant, but the value is too large for the type int. You need to use a suffix to change the type of the literal, i.e.

long long num3 = 100000000000LL;

The suffix LL makes the literal into type long long. C is not "smart" enough to conclude this from the type on the left, the type is a property of the literal itself, not the context in which it is being used.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • 49
    Back when this answer was written it was probably correct, but now the C++ standard says that the type of an integer literal with no suffix is the first of `int`, `long int`, and `long long int` in which its value can be represented. [C++ §2.14.2/2] Therefore now there's no need to add the 'LL' suffix onto an integer literal that's too big for other types. – bames53 Jan 04 '12 at 21:48
  • 8
    The reason this was a problem before wasn't because C++ wasn't 'smart' enough to determine the literal type from the type of the variable being assigned to, it would simply have been because the compiler extension didn't implement the extended integer type such that it would work well with the standard language. C++ now has rules such that any extended integer types will integrate better with the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf – bames53 Jan 04 '12 at 21:49
  • 5
    @unwind I think the answer should be edited according to these suggestions. – Antonio Jun 22 '13 at 20:12
28

Try:

num3 = 100000000000LL;

And BTW, in C++ this is a compiler extension, the standard does not define long long, thats part of C99.

Arkaitz Jimenez
  • 22,500
  • 11
  • 75
  • 105
6

It depends in what mode you are compiling. long long is not part of the C++ standard but only (usually) supported as extension. This affects the type of literals. Decimal integer literals without any suffix are always of type int if int is big enough to represent the number, long otherwise. If the number is even too big for long the result is implementation-defined (probably just a number of type long int that has been truncated for backward compatibility). In this case you have to explicitly use the LL suffix to enable the long long extension (on most compilers).

The next C++ version will officially support long long in a way that you won't need any suffix unless you explicitly want the force the literal's type to be at least long long. If the number cannot be represented in long the compiler will automatically try to use long long even without LL suffix. I believe this is the behaviour of C99 as well.

sellibitze
  • 27,611
  • 3
  • 75
  • 95
2

your code compiles here fine (even with that line uncommented. had to change it to

num3 = 100000000000000000000;

to start getting the warning.

Omry Yadan
  • 31,280
  • 18
  • 64
  • 87
  • What compiler? In C++, an integer literal is the smaller of int or long that it fits in. In C99, it's the smallest of int, long, long long. So when bolting long long on to C++ as a non-standard extension, perhaps your compiler has also adopted the C99 rules for literals. – Steve Jessop Sep 22 '09 at 09:42
  • gcc version 4.3.2 (Debian 4.3.2-1.1) on a 64bit linux system. – Omry Yadan Sep 22 '09 at 09:56
  • @SteveJessop A bit late perhaps: but long is NOT necessarily 64 bits. Most of the time it is, but you have no guarantees it will be everywhere. The only guarantee you have is that it is at least as big as an int, which in turn is at least as big as a short int, which in turn is at least as big as a char. Finally, char is defined as big enough to represent every character in the _implementation's_ basic charset (typically 8-bits). – pauluss86 Nov 08 '13 at 14:15
  • @pauluss86: I wasn't talking about guarantees. Omry said that he was using gcc 4.3.2 on a 64 bit Debian system. I observed that this explained what he was seeing since (I happened to know as a matter of general knowledge) gcc is configured by default on such systems to use a 64 bit `long` in line with that OS's LP64 ABI. – Steve Jessop Nov 08 '13 at 22:08
  • @SteveJessop I'm not suggesting your comment is wrong! Only pointing out that the assumption that a long is always 64 bits everywhere, which unfortunately a lot of people think, is dangerous. – pauluss86 Nov 09 '13 at 00:17
  • @pauluss86: right, in particular `long` is 32 bits wide on Windows. So whoever these people are, if they weren't recently programming Java I don't think they have much excuse for their mistake :-) – Steve Jessop Nov 09 '13 at 00:30
0

Note:

  1. remove semicolon after the header file
  2. use %lu instead of just %u
  3. long long num3 = 100000000000LL;

Replace these things and you are good to go :)

charlie
  • 3
  • 1
  • 1
    Your second point isn't correct. OP's uses of `%u` coincide with the result of `sizeof(...)` -- which is `std::size_t`; the correct format specifier for `size_t` is `%zu`. Also, this question has been adequately answered for **over 10 years**, and this answer does not expand or provide any different details to OP's question (actually, it provides less information). – Human-Compiler Jul 01 '21 at 14:32