cinteger-overflowunsigned-long-long-int

Why does gcc ignore the "unsigned" data type statements?


One of the numbers for testing my function needs 64 bits to be stored and since I'm coding in C I need an unsigned long long to store such a number. When I try to define a variabile with that data type and assign the number to it gcc will tell me "integer constant is so large that it is unsigned" even though I already specified it was.

Edit: the warning was removed by adding ULL at the end of the integer.

I tried debugging and everything in my function works except for those cases where the number needs 64 bits. In my function at some point I need to reverse the number in question. For that I made a new variabile called reversed and used the data type unsigned long long.

unsigned long long num = 18446744073709551615ULL;

...

unsigned long long reversed = 0, i;
for(i = num; i > 0; i /= 10) {
    reversed *= 10;
    reversed += i % 10;
}

Through the debugger I watched the process and the variabile reversed gets an overflow on the last cycle of the for, when it gets multiplied by 10. I tried changing "unsigned long long" to "unsigned long long int" but nothing changed. I also tried casting every single other number used to make additions and multiplications as unsigned long long but that didn't work.

Sorry for any lack of information


Solution

  • When I try to define a variabile with that data type and assign the number to it gcc will tell me "integer constant is so large that it is unsigned" even though I already specified it was.

    You did not specify the integer constant was unsigned. unsigned long long num = 18446744073709551615; specifies that num is unsigned. It says nothing about 18446744073709551615.

    18446744073709551615 is an integer constant. The fact it is going to be assigned to num does not make it take on the properties of num. It is merely an integer constant with no indication of whether it should be unsigned or not.

    C automatically assigns types to integer constants. For decimal constants with no suffix, it normally uses the first of int, long int, and long long int in which the value fits. Your value, 18,446,744,073,709,551,615 does not fit into any of those types. Technically, then, it falls into a strange category in the C standard: “If an integer constant cannot be represented by any type in its list and has no extended integer type, then the integer constant has no type.” (C 2018 6.4.4.1 6.) The compiler chose to give it the type unsigned long long int and is warning you about this problem.

    Adding the ull suffix fixes this, as it denotes the type to be unsigned long long int, into which the value fits. Simply adding u would also work, as then the types that are automatically considered include unsigned long long int.

    In my function at some point I need to reverse the number in question.

    That will not work because the decimal numeral formed by reversing the decimal digits representing your number will not fit into the unsigned long long int that your C implementation uses. No arithmetic can compute the correct result because the correct result cannot be represented in the unsigned long long int type.

    You could reverse the digits using a string of characters, or you could output the reversed digits by printing them one at a time (or a few at a time) instead of having the entire number all at once.