views:

278

answers:

2

I have following array, that I need to operate by hand on bitmaps.

const unsigned int BITS[32] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 
                               2048, 4096, 8192, 16384, 32768, 65536, 131072, 
                               262144, 524288, 1048576, 2097152, 4194304, 
                               8388608, 16777216, 33554432, 67108864, 134217728, 
                               268435456, 536870912, 1073741824, 2147483648};

Unfortunately, when compiled I get

warning: this decimal constant is unsigned only in ISO C90

How can I remove this?

+4  A: 

Your constant has to be specified as unsigned too, use

2147483648UL

(UL = Unsigned Long), or simply

2147483648U

for an unsigned int.

As your code is right now, a constant, which is by default a plain int, and hence signed, is assigned to an unsigned int, which generates your warning.

Pieter
That worked, thanks a lot :-)
gruszczy
Pedandically speaking, the error isn't that from the fact the (plain int) constant is assigned to an unsigned int; the assignment is irrelevant. The error is because the value of "2147483648" is too large to be a signed int, and so there's an overflow in generating the signed int constant in the first place.
Brooks Moses
Actually, the real reason for the warning is that the compiler has to choose `unsigned long` for the constant type. (Note, again, this constant is not `unsigned int`, it is `unsigned long`.) And it has to choose it in C89/90 specifically, instead of choosing a larger signed type (which it might support) or following C99 rules and choosing `long long`. This is what the warning is about and why it refers to `ISO C90`. In C99, for example, an unsuffixed decimal constant would never be given an unsigned type.
AndreyT
AndreyT: Thanks for the clarification!
Brooks Moses
+4  A: 

Integer literals in C are, by default, of type "signed int". The last number there is too large to be represented as a signed 32-bit integer, and so you need to tell the compiler that it's an unsigned integer by suffixing it with "U", as:

2147483648U

Note that you can also add a suffix of "L" to make it a "long", but on many systems that's still 32-bit and thus irrelevant.

Also, there's a much less error-prone (and easier-to-read) way to write this code, with the bit-shift operator:

const unsigned int BITS[32] = {1U, 1U<<1, 1U<<2, 1U<<3, 1U<<4,
                               /* and so on */
                               1U<<31};

Or, writing in hexadecimal, if you don't like bit shifts for some reason:

const unsigned int BITS[32] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
                               /* and so on */
                               0x80000000U};
Brooks Moses
Why compiler treats it then as an int, rather then automatically turn it into uint? Especially, that it exactly knows in what type it will be stored.
gruszczy
In a lot of cases you can't know what type a constant is (for instance, as a function argument in a varargs function) so it has to be specified explicitly. It's confusing to have the type be implied some times and need to be specified explicitly in others, and also confusing to have the same constant be different types on systems with different int sizes. Also, because C never does type inference of that sort, adding it for this one case would complicate the parser quite a lot without significant benefit.
Brooks Moses
@gruszczy: In C89/90 an unsuffixed decimal constant must be interpreted as `int`, `long` or `unsigned long` (whichever fits first). In C99 it must be interpreted as `int`, `long` or `long long` (whichever fits first). This what the compiler is trying to say by this warning. Apparently, on this platform `long` has the same size as `int`. The compiler is basically saying: "maybe you were trying to create a `signed long` connstant or maybe even a `long long` constant, but by the C89/90 rules I have to make it `unsigned long`.
AndreyT
OK, thanks. And by the way: version with operators is indeed better. I didn't know, I could do that outside of a function, in an array initializer. Thanks a lot.
gruszczy
@gruszczy: Just keep in mind that version with operators does not automatically protect you from overflow. This is something you have to watch for yourself, i.e. you'll have to specify the `u` or `ul` suffix anyway.
AndreyT
I'll try to remember about that. I am not used to those UL and L markers. I am programming in Python most of the time, so I need to get used to all that :-) Thanks for the advice.
gruszczy
In fact, the situation is quite a bit complicated. It's not as easy as "it's always signed int": There are differences between all of C90, C99 and C++ and there are different treatment of hex/oct and decimal literals. It's all causing a big headache.
Johannes Schaub - litb