2

以下を印刷すると -1 になるのはなぜですか?

unsigned long long int largestIntegerInC = 18446744073709551615LL;

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

lluの代わりに使用する必要があることはわかってdいますが、18446744073709551615LL の代わりに -1 が返されるのはなぜですか?

オーバーフローのせいですか?

4

6 に答える 6

4

C(99)ではLLONG_MAX、typeの最大値はlong long int少なくとも。であることが保証されています9223372036854775807。anの最大値は、unsigned long long int少なくとも18446744073709551615、2 64 -1(0xffffffffffffffff)であることが保証されています。

したがって、初期化は次のようになります。

unsigned long long int largestIntegerInC = 18446744073709551615ULL;

(。に注意してくださいULL。)largestIntegerInCはタイプなのでunsigned long long int、正しいフォーマット指定子を使用して印刷する必要があります"%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’

上記の2番目printf()は間違っています、それは何でも印刷できます。を使用しています。これは、を期待している"%d"ことを意味しますが、を取得します。これは(ほとんどの場合)と同じサイズではありません。出力として取得する理由は、(不運な)運と、マシン上で2の補数表現を使用して数値が表されるという事実によるものです。printf()intunsigned long long intint-1


これがどのように悪いかを確認するために、次のプログラムを実行してみましょう。

#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;
}

私のMacbookでは、でプログラムを実行すると"%d %d %d"が得-1 -1 42られ、Linuxマシンでは、同じ形式の同じプログラムでが得られます-1 42 -1。おっと。


実際、変数に最大unsigned long long int数を格納しようとしている場合は、を含めて使用する必要があります。または、変数にassingを格納する必要があります。largestIntegerInClimits.hULLONG_MAX-1

#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;
}

上記のプログラムでは、との両方largestIntegerInCにtypenextの可能な最大値が含まれていますunsigned long long int

于 2010-02-16T06:15:04.093 に答える
3

これは、すべてのビットが 1 に設定された数値を渡しているためです。2 の補数の符号付き数値として解釈されると、-1 になります。この場合、おそらくこれらの 1 ビットのうち 64 ビットすべてではなく 32 ビットしか見ていませんが、実際の違いはありません。

于 2010-02-16T06:04:10.220 に答える
1

2 の補数演算では、符号付きの値 -1 は符号なしの最大値と同じです。

2 の補数の負の数のビット パターンを考えてみましょう (私は 8 ビット整数を使用していますが、パターンはサイズに関係なく適用されます)。

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

したがって、負の 1 にはすべて 1 のビット パターンがあり、これは最大の符号なし値のビット パターンでもあることがわかります。

于 2010-02-16T06:03:11.190 に答える
0

いいえ、オーバーフローはありません。これは、値全体を出力していないためです。

18446744073709551615は0xFFFFFFFFFFFFFFFFと同じです。それを処理するときprintf %d、変換のために32ビット(または64ビットCPUの場合は64ビット)のみを取得し、それらは符号付きの値-1です。

printf代わりに変換が行われた場合は%u、4294967295(32ビット)または18446744073709551615(64ビット)のいずれかが表示されます。

オーバーフローとは、値が増加して、割り当てられたストレージに収まらない場合です。この場合、値は適切に割り当てられますが、完全には取得されていません。

于 2010-02-16T06:24:38.613 に答える
0

符号付き 32 ビット数値の形式を使用したため、-1 が得られました。 printf()渡された数値の大きさを内部的に判断できないため、varargs リストから最初の 32 ビットを取り出して、出力する値として使用します。署名された形式を指定したため、そのように出力され、0xffffffff は -1 の 2 の補数表現です。

于 2010-02-16T06:03:30.963 に答える
0

コンパイラの警告で理由を確認できます (すべきです)。そうでない場合は、最高の警告レベルを設定してみてください。VS では、警告 C4245: 'initializing' : conversion from '__int64' to 'unsigned __int64', signed/unsigned mismatch. という警告が表示されます。

于 2010-02-16T06:12:02.197 に答える