Printing unsigned long long using %d

一笑奈何 提交于 2019-12-11 01:14:42

问题


Why do I get -1 when I print the following?

unsigned long long int largestIntegerInC = 18446744073709551615LL;

printf ("largestIntegerInC = %d\n", largestIntegerInC);

I know I should use llu instead of d, but why do I get -1 instead of 18446744073709551615LL?

Is it because of overflow?


回答1:


In C (99), LLONG_MAX, the maximum value of long long int type is guaranteed to be at least 9223372036854775807. The maximum value of an unsigned long long int is guaranteed to be at least 18446744073709551615, which is 264−1 (0xffffffffffffffff).

So, initialization should be:

unsigned long long int largestIntegerInC = 18446744073709551615ULL;

(Note the ULL.) Since largestIntegerInC is of type unsigned long long int, you should print it with the right format specifier, which is "%llu":

$ cat test.c
#include <stdio.h>

int main(void)
{
    unsigned long long int largestIntegerInC = 18446744073709551615ULL;
    /* good */
    printf("%llu\n", largestIntegerInC);
    /* bad */
    printf("%d\n", largestIntegerInC);
    return 0;
}
$ gcc  -std=c99 -pedantic test.c
test.c: In function ‘main’:
test.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’

The second printf() above is wrong, it can print anything. You are using "%d", which means printf() is expecting an int, but gets a unsigned long long int, which is (most likely) not the same size as int. The reason you are getting -1 as your output is due to (bad) luck, and the fact that on your machine, numbers are represented using two's complement representation.


To see how this can be bad, let's run the following program:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    const char *fmt;
    unsigned long long int x = ULLONG_MAX;
    unsigned long long int y = 42;
    int i = -1;
    if (argc != 2) {
        fprintf(stderr, "Need format string\n");
        return EXIT_FAILURE;
    }
    fmt = argv[1];
    printf(fmt, x, y, i);
    putchar('\n');
    return 0;
}

On my Macbook, running the program with "%d %d %d" gives me -1 -1 42, and on a Linux machine, the same program with the same format gives me -1 42 -1. Oops.


In fact, if you are trying to store the largest unsigned long long int number in your largestIntegerInC variable, you should include limits.h and use ULLONG_MAX. Or you should store assing -1 to your variable:

#include <limits.h>
#include <stdio.h>

int main(void)
{
    unsigned long long int largestIntegerInC = ULLONG_MAX;
    unsigned long long int next = -1;
    if (next == largestIntegerInC) puts("OK");
    return 0;
}

In the above program, both largestIntegerInC and next contain the largest possible value for unsigned long long int type.




回答2:


It's because you're passing a number with all the bits set to 1. When interpreted as a two's complement signed number, that works out to -1. In this case, it's probably only looking at 32 of those one bits instead of all 64, but that doesn't make any real difference.




回答3:


In two's complement arithmetic, the signed value -1 is the same as the largest unsigned value.

Consider the bit patterns for negative numbers in two's complement (I'm using 8 bit integers, but the pattern applies regardless of the size):

 0 - 0x00
-1 - 0xFF
-2 - 0xFE
-3 - 0xFD

So, you can see that negative 1 has the bit pattern of all 1's which is also the bit pattern for the largest unsigned value.




回答4:


You used a format for a signed 32-bit number, so you got -1. printf() can't tell internally how big the number you passed in is, so it just pulls the first 32 bits from the varargs list and uses them as the value to be printed out. Since you gave a signed format, it prints it that way, and 0xffffffff is the two's complement representation of -1.




回答5:


You can (should) see why in compiler warning. If not, try to set the highest warning level. With VS I've got this warning: warning C4245: 'initializing' : conversion from '__int64' to 'unsigned __int64', signed/unsigned mismatch.




回答6:


No, there is no overflow. It's because it isn't printing the entire value:

18446744073709551615 is the same as 0xFFFFFFFFFFFFFFFF. When printf %d processes that, it grabs only 32 bits (or 64 bits if it's a 64-bit CPU) for conversion, and those are the signed value -1.

If the printf conversion had been %u instead, it would show either 4294967295 (32 bits) or 18446744073709551615 (64 bits).

An overflow is when a value increases to the point where it won't fit in the storage allocated. In this case, the value is allocated just fine, but isn't being completely retrieved.



来源:https://stackoverflow.com/questions/2270966/printing-unsigned-long-long-using-d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!