I have a file test.cpp that looks like this:
void f(const int n) {
unsigned char *a=new unsigned char[n];
delete[] a;
}
int main() {
f(4);
return 0;
}
Compiling it in 64-bit GCC with the -Wsign-conversion
flag produces the warning:
test.cpp:2:39: warning: conversion to ‘long unsigned int’ from ‘const int’ may change the sign of the result [-Wsign-conversion]
(line 2 is the line in which new
is called). It seems strange to me that GCC should give this warning about allocating an array, but the following things are even stranger:
unsigned char *a=new unsigned char[(long unsigned int)n];
does not get rid of the warning, nor does using static_cast<long unsigned int>()
.No warning is produced if f
is defined with the signature void f(T n)
, where T
is
It does however produce warnings when T
is any const signed integer type smaller than 64-bits.
Bearing in mind that I'm on a 64-bit (Linux) machine, why does the sign-conversion warning care about the constness and size of n
in this case, and why doesn't type casting fix the problem?
Note 1: I wanted to test this under another compiler, but the Comeau site is down, and I don't have access to any other compilers, so I can't tell if this is standard-compliant behaviour, or a GCC bug.
Note 2: test.cpp is a minimal example of a problem from a "real" C++ file that I have in which the best way for me to get rid of the warning was to surround the offending line with:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
// ...
#pragma GCC diagnostic pop
Some properties of the unsigned long long int data type are: An unsigned data type stores only positive values. It takes a size of 64 bits. A maximum integer value that can be stored in an unsigned long long int data type is 18, 446, 744, 073, 709, 551, 615, around 264 – 1(but is compiler dependent).
unsigned long is required to be at least 32 bits. unsigned long long is required to be at least 64 bits. (Actually the requirements are stated in terms of the ranges of values they can represent.) As you've seen, this is consistent with them both being the same size, as long as that size is at least 64 bits.
Unsigned integer constant is an integer constant which has the permissible range from 0 to 65536. Thus significance of declaring a constant as unsigned almost doubles the size of the largest possible value.
Unsigned long variables are extended size variables for number storage, and store 32 bits (4 bytes).
I'm a little flaky on the details, but it seems to me that the issue is actually in sign extension (since size_t is most likely an unsigned long on your system). Consider the following code:
#include <stdio.h>
void f(const int n) {
unsigned long int b = static_cast<long unsigned int>(n);
printf ("0x%llx == %lld\n", b, b);
}
int main() {
unsigned long int c = 1;
c <<= 31;
printf ("0x%llx == %lld \n", c, c);
f(c);
return 0;
}
it prints:
0x80000000 == 2147483648
0xffffffff80000000 == -2147483648
Note that I intentionally picked a value that means a negative as an int, but not as a long. The first print should actually be 0x0000000080000000. If I picked a simple -1, it would still get sign-extended to long as a -1, but this one gives something completely different.
Of course if you explicitly cast it to an unsigned you also get something else, but my guess is that the compiler is more worried about the implicit conversions (the up-convert to 64bit in this case) that you're more likely to miss ("what could possibly go wrong with more bits?")
Another hint it's the upconvert that's bugging us (if not, i'll be happy to hear another explanation):
int main() {
int n = 1;
const long int a = static_cast<long int> (n);
const int b = static_cast<int> (n);
char* ap = new char [a];
char* bp = new char [b];
}
This complains only on b
test.cpp: In function ?int main()?:
test.cpp:8:27: warning: conversion to ?long unsigned int? from ?const int? may change the sign of the result [-Wsign-conversion]
char* bp = new char [b];
so we've ruled out the option that function arguments passing is to blame
Now, if I may further speculate, perhaps that warning is specific to memory allocations (note that you don't get it from simply casting n to long), because the compiler would have wanted to do some allocation magic given a constant size. Imagine the shock it got when it saw what you're trying to do.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With