tags:

views:

94

answers:

6

The following code is producing a warning when I compile it on 32-bit systems: 1087: warning: integer constant is too large for "long" type; how can I fix this so I don't get that warning and it works correctly on 32-bit?

A valid input for this is:

unsigned char str[] = "\x00\x17\x7c\x3a\x67\x4e\xcb\x01";

and the mypow function returns unsigned long long.

     unsigned long long high, low, nano;
     high = // line 1087
         (str[7]&0xff) * mypow(2,56) +
         (str[6]&0xff) * mypow(2,48) +
         (str[5]&0xff) * mypow(2,40) +
         (str[4]&0xff) * mypow(2, 32);
     low =
         (str[3]&0xff) * mypow(2,24) +
         (str[2]&0xff) * mypow(2,16) +
         (str[1]&0xff) * mypow(2,8) +
         (str[0]&0xff);
     nano = ((high + low)/10000000) - (unsigned long long)11644473600;
     return localtime((time_t*)&nano);
+6  A: 

If you are using a constant in your code that won't fit inside 32 bits, add an LL to the end of it so the compiler knows that it's supposed to be a 'long long' type. For example, the constant at the end of the nano = line should be 11644473600LL. The current code casts the constant to a long long, but the constant itself is a regular long since there is no explicit LL suffix.

bta
Depending on the type, `ULL` might be the right suffix.
jkerian
The language guarantees that the constant will have the larger type if it doesn't fit into smaller type. There's never a need to add any suffixes, unless you want to forcefully give a *small* constant a *larger* type or switch from signed to unsigned.
AndreyT
In this particular case, what would be the point to explicitly give that `long` constant the `LL` suffix, if it is explicitly cast to `unsigned long long` anyway? Just for cleaner code it might make sense (i.e. `ULL` instead of the cast), but it is a matter of personal preference.
AndreyT
In other words, this answer does not really answer the actual question: why the compiler is issuing a warning. The correct answer is most likely because the OP is compiling in C89/90 mode, where `long long` types are non-standard.
AndreyT
@AndreyT- Most 32-bit compilers won't (by default) interpret constants as 64-bit numbers unless you explicitly write them as such. Since the constant `11644473600` does not have a suffix, the compiler interprets it as a long int and throws a warning because the number overflows the long int. The cast isn't the problem; as written in the sample, the code is casting a 32-bit number into a 64-bit number. The compiler's interpretation of the number as a 32-bit value is the problem, and explicitly marking the number as "long long" forces the compiler to treat it as a 64-bit number.
bta
@bta: AndreyT's point is that if that number doesn't fit into a `long`, and the compiler doesn't give it the `long long` type, then the compiler is broken.
caf
@bta: No. The reason, once again, has nothing to do with the compiler being 32-bit or 64-bit. Any C99 compiler is required to treat a sufficiently large constant as `long long`, regardless of whether it is a 32-bit or 64-bit compiler. Suffixes do not matter. Any C99 compiler that refuses to treat this constant (without any suffixes) as `long long` is broken and is immediately laughed off the market.
AndreyT
The reason for the warning in this case is solely the support for `long long` as *standard* type. C89/90 compilers do not support `long long` as standard type, which is why they simply can't *implicitly* treat this constant as a `long long` without at least issuing a warning. Again, this applies regardless of whether the compiler is 32- or 64-bit.
AndreyT
+1  A: 

you should use the stdint.h defined integer types for cross platform portability.

for example you should try using uint64_t instead of unsigned long long. That way you know exactly how many bits you are getting and it is the same on all platforms.

luke
While true enough, a long long is guaranteed to be atleast 64 bits. However, the real issue is that the compiler thinks the 11644473600 literal is a long, but it doesn't fit in a long.
nos
@nos - you're right. sorry, I guess I didn't read the question too closely :) just saw 32/64 bit, integer types, compiler warnings... and it lit the little stdint.h bulb in the back of my head.
luke
+2  A: 

It thinks the 1000000 is a 32-bit value. Be explicit about it being long:

nano = ((high + low)/10000000L) - 11644473600L;

EDIT: ULL would be the proper suffix.

EboMike
+2  A: 

I believe you need to do 11644473600ULL

mathepic
+2  A: 

The most likely correct answer to your question is that you must be using your C compiler in C89/90 mode (or maybe in C++ mode?). In both C89/90 and C++ the largest integer type is long. There's no such type as long long in these languages. Yet, some compilers support the long long as a non-standard extension. When you use a constant that is too large for long type in your code the compiler has to either reject your code or promote the constant to the non-standard long long type. In the latter case the warning is issued in order to inform you about the non-standard type being implicitly introduced into your code.

While the solution with LL or ULL suffix might work to suppress the warning, if you really want to use the long long type in your code I'd still recommend you to compile your code in C99 mode, where this type is standard. In C99 mode the warning should disappear by itself, regardless of any suffixes.

AndreyT
A: 

Use -std=c99 on the gcc command line and the warning will go away, because C99 has well-defined behavior for integer constants this large.

R..