web-dev-qa-db-ja.com

デフォルトではintではない整数リテラルのタイプ?

私はちょうど答えました この質問 、forループで100億まで繰り返すのに、10億まで繰り返すよりもはるかに長い時間がかかる(OPは実際には10分後に中止した)理由を尋ねました:

for (i = 0; i < 10000000000; i++)

私や他の多くの人の明白な答えは、反復変数が32ビット(100億に達することはありません)であり、ループが無限ループになるためであるというものでした。

しかし、私はこの問題に気づきましたが、それでもコンパイラー内で実際に何が起こっているのか疑問に思います。

リテラルにはLが追加されていないため、IMHOもint型である必要があり、したがって32ビットである必要があります。したがって、オーバーフローのため、到達可能になるには範囲内の通常のintである必要があります。 intから到達できないことを実際に認識するために、コンパイラはそれが100億であることを認識し、したがって32ビットを超える定数と見なす必要があります。

そのようなリテラルは、Lが追加されていなくても、自動的にフィッティング(または少なくとも実装定義)範囲(この場合は少なくとも64ビット)にプロモートされますか?これは標準的な動作ですか?それとも、オーバーフローによるUB(整数オーバーフローは実際にはUB)のように、舞台裏で何か違うことが起こっていますか?標準からのいくつかの引用は、もしあれば、素晴らしいかもしれません。

元の質問はCでしたが、異なる場合はC++の回答にも感謝します。

C++に関する限り:

C++ 11、[Lex.icon]¶2

整数リテラルのタイプは、その値を表すことができる表6の対応するリストの最初のものです。

また、表6は、接尾辞と10進定数のないリテラルについて、次のように示しています。

int
long int
long long int

(興味深いことに、16進定数または8進定数の場合もunsignedタイプが許可されますが、それぞれがafterリスト内の対応する符号付きのものになります)

したがって、その場合、定数がlong int(または、long long intが32ビットすぎる場合はlong int)として解釈されていることは明らかです。

「リテラルが大きすぎる」とコンパイルエラーが発生することに注意してください。

プログラムの変換単位の1つに、許可されたタイプのいずれでも表現できない整数リテラルが含まれている場合、プログラムの形式が正しくありません。

(同上、¶3)

これはすぐにわかります このサンプルでは 、ideone.comが32ビットコンパイラを使用していることを思い出させます。


質問がCについてであることがわかりました...まあ、それは多かれ少なかれ同じです:

C99、§6.4.4.1

整数定数の型は、その値を表すことができる対応するリストの最初のものです。

c ++標準と同じリスト。


補遺:C99とC++ 11はどちらも、他のすべてが失敗した場合に、リテラルを「拡張整数型」(つまり、他の実装固有の整数型)にすることもできます。 (C++ 11、[Lex.icon]¶3; C99、§6.4.4.1¶5表の後)

34
Matteo Italia

ISO/IEC 9899:TC2委員会ドラフト— 2005年5月6日というラベルの付いたC標準のドラフトから、ルールはMatteoが見つけたC++ルールと非常に似ています。

5整数定数の型は、その値を表すことができる対応するリストの最初のものです。

Suffix      Decimal Constant          Octal or Hexadecimal Constant
-------------------------------------------------------------------
none        int                       int
            long int                  unsigned int
            long long int             long int
                                      unsigned long int
                                      long long int
                                      unsigned long long int

u or U      unsigned int              unsigned int
            unsigned long int         unsigned long int
            unsigned long long int    unsigned long long int

l or L      long int                  long int
            long long int             unsigned long int
                                      long long int
                                      unsigned long long int
Both u or U unsigned long int         unsigned long int
and l or L  unsigned long long int    unsigned long long int

ll or LL    long long int             long long int
                                      unsigned long long int

Both u or U unsigned long long int    unsigned long long int
and ll or LL 
11
sarnold

コンパイラ内で実際に何が起こっているのかまだ疑問です

コンパイラがコードを解釈する方法に興味がある場合は、アセンブラを参照してください。

10000000000:

400054f:
mov    -0x4(%rbp),%eax
mov    %eax,-0x8(%rbp)
addl   $0x1,-0x4(%rbp)
jmp    40054f <main+0xb>

したがって、10000000000を10000に置き換えると、無限ループにコンパイルされます。

....
test   %al,%al
jne    400551
1
fghj