0

I have a chunk of code generated by a script, and the code involves some integer constants. I ran into a strange problem: one of the constants is equal to -2147483648 (minimum signed int32), and Visual Studio generates the following error: unary minus operator applied to unsigned type, result still unsigned (which is especially strange since I don't have treat warnings as errors enabled).

Apparently it sees an integer that doesn't fit in the signed type, makes it unsigned, and only then applies the unary minus. I suppose the result would still be correct as it will be casted to int (which is actually a template argument), but I'd like to avoid the warning. Is it just a VS feature or does the standard have anything to say about it?

Here's the offending line:

typedef Proto_Int<-2147483648,32> Typeinfo_77;
riv
  • 6,846
  • 2
  • 34
  • 63
  • 4
    I don't know what the problem is, but there are constants for max and min "types" in the standard: `std::numeric_limits::min();` and `std::numeric_limits::max();` See: http://en.cppreference.com/w/cpp/types/numeric_limits – Brandon Dec 23 '14 at 01:47
  • That's why I mentioned that it is generated by a script. The constant is read from a file, and it (normally) has nothing to do with numeric limits. – riv Dec 23 '14 at 01:51
  • If it's "read from a file" as you describe.. How exactly did you get it as a "Template" argument as shown above? I answered the question in the title, I suppose. Not the question about whether the standard has anything to say about it. MSDN says: http://msdn.microsoft.com/en-us/library/4kh09110.aspx – Brandon Dec 23 '14 at 01:57
  • I have a python script which generates a large .h file with a bunch of declarations like these. Anyway, replaced it with (x+1)-1, ugly but will have to do =\ – riv Dec 23 '14 at 02:01
  • 1
    Well.. just so you know, MSDN (from the link above) says: `You can avoid C4146 by using INT_MIN from limits.h, which has the type signed int.` You could just make your script replace `-2147483648` with `INT_MIN`. – Brandon Dec 23 '14 at 02:03
  • You can [*Suppress Compiler Warnings*](http://msdn.microsoft.com/en-us/library/jj715718.aspx). Doesn't it work? – Ripple Dec 23 '14 at 02:07

2 Answers2

1

In C++ negative numbers are stored as positive number with (-) negative sign.

That is why min int is defined as,

#define INT_MIN (-2147483647 - 1)

For int C++ does not understand 2147483648. So if possible you can also write 2147483648 as (-2147483647 - 1)

Pranit Kothari
  • 9,721
  • 10
  • 61
  • 137
  • I guess I'll have to, even if it requires an ugly hack in the script that generates the code. However, I still don't understand why it generated an *error* instead of just a warning. – riv Dec 23 '14 at 01:56
  • The way negative numbers are stored is implementation-defined, with 3 options: 2's-complement, 1's-complement, and sign-and-magnitude. Only sign-and-magnitude actually stores negative numbers just by setting the sign bit -- and 2's-complement is practically universal these days. – Keith Thompson Dec 23 '14 at 02:12
1

An unsuffixed decimal integer literal like 2147483648 is of type int, long int, or long long int, specifically the first of those types in which its value can be represented.

On a system with 32-bit int, 2147483648 will be of type long int or long long int.

But your compiler's warning message indicates that it's following a different set of rules. In the 1990 C standard, an unsuffixed decimal integer constant is of type int, long int, or unsigned long int (there was no type long long). So under C90 rules, 2147483648 would likely be of type unsigned long int. Applying the unary - operator to it doesn't change the type, and under the rules of unsigned arithmetic the result is 2147483648.

Although the rule that such a literal is of type int or long int is present in the 1998, 2003, and 2011 ISO C++ standards, you seem to be using a compiler that behaves inconsistently with any of those standards.

If your template expects an int, then the unsigned long int value 2147483648 will be implicitly converted to int. The result of such a conversion (when the value exceeds INT_MAX is implementation-defined, but is very likely to be -2147483648, which is INT_MIN for a 32-bit 2's-complement system.

You say the C++ source is generated by a Python script, and that the value isn't necessarily -2147483648. I think you'll just have to add a special case so that the value -2147483648 is generated as (-2147483647-1). (I do recommend the parentheses; they're not necessary in this particular case, but they're harmless and can avoid operator precedence problems if you generate similar constants in other contexts.)

Note that the values of INT_MIN and INT_MAX can vary for different implementations. If you might need to target different C++ implementations, you should probably make your Python script smart enough to deal with different bounds.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631