Consider the following code:
#include <stdio.h>
int main(void) {
printf("%llu\n", 18446744073709551615);
printf("%llu\n", 18446744073709551615ULL);
return 0;
}
Upon compilation (gcc -std=c18
), I get the following warnings:
test1.c: In function ‘main’:
test1.c:4:26: warning: integer constant is so large that it is unsigned
4 | printf("%llu\n", 18446744073709551615);
| ^~~~~~~~~~~~~~~~~~~~
test1.c:4:20: warning: format ‘%llu’ expects argument of type ‘long long unsigned int’, but argument 2 has type ‘__int128’ [-Wformat=]
4 | printf("%llu\n", 18446744073709551615);
| ~~~^ ~~~~~~~~~~~~~~~~~~~~
| | |
| | __int128
| long long unsigned int
The C standard section 6.4.4.1.5 and 6.4.4.1.6 say:
The type of an integer constant is the first of the corresponding list in which its value can be represented.
If an integer constant cannot be represented by any type in its list, it may have an extended integer type, if the extended integer type can represent its value. If all of the types in the list for the constant are signed, the extended integer type shall be signed. If all of the types in the list for the constant are unsigned, the extended integer type shall be unsigned. If the list contains both signed and unsigned types, the extended integer type may be signed or unsigned. 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.
From the above it is clear that as ULONG_MAX
cannot fit in int
, long int
and long long int
, the compiler will try the signed extended integer types; as ULONG_MAX
does fit inside __int128
, that then becomes the type of the integer constant, as can be seen from the second warning message.
This is all expected behavior, but the issue I am facing is that clearly __int128
is a signed type, as is expected from the C standard. But then why does the first warning message ("integer constant is so large that it is unsigned") say that the constant is treated as unsigned? That makes no sense to me, as according to 6.4.4.1.6 only the signed extended integer types are checked, so how is the integer constant being treated as unsigned?
To clarify the question a bit, my issue is not with printf
; the format warning is expected, I just left it there to show that the constant is of type __int128
.
Consider the code:
#include <stdio.h>
int main(void) {
__int128 a = 18446744073709551615;
unsigned long long b = 18446744073709551615;
return 0;
}
Compiling this gives the warning:
test2.c: In function ‘main’:
test2.c:4:22: warning: integer constant is so large that it is unsigned
4 | __int128 a = 18446744073709551615;
| ^~~~~~~~~~~~~~~~~~~~
test2.c:5:32: warning: integer constant is so large that it is unsigned
5 | unsigned long long b = 18446744073709551615;
| ^~~~~~~~~~~~~~~~~~~~
My issue is that since the constant is of type __int128
, why does the compiler say it is unsigned? Obviously __int128
is a signed type.