web-dev-qa-db-ja.com

長い値に対して明示的にLまたはULを宣言する理由は何ですか

例から

unsigned long x = 12345678UL

コンパイラは、4バイト(32ビット)のメモリを設定するために、上記の例で「長い」だけを見る必要があることを常に学びました。問題は、L/ULが長いと宣言した後でも、L/ULを長い定数で使用する必要がある理由です。

28
Shash

接尾辞LまたはULが使用されない場合、コンパイラはリストの定数を含むことができる最初の型を使用します(C99標準の6.4.4:5節の詳細を参照してください。 10進定数、リストはintlong intlong long intです。

その結果、ほとんどの場合、接尾辞を使用する必要はありません。プログラムの意味は変わりません。ほとんどのアーキテクチャでxの初期化例の意味は変わりませんが、long longとして表現できない番号を選択した場合は変わります。接尾辞のU部分が必要な例については、codebauerの回答も参照してください。


プログラマーが定数のタイプを明示的に設定したい場合があります。 1つの例は、可変長関数を使用する場合です。

printf("%lld", 1LL); // correct, because 1LL has type long long
printf("%lld", 1);   // undefined behavior, because 1 has type int

接尾辞を使用する一般的な理由は、計算結果がオーバーフローしないようにすることです。 2つの例は次のとおりです。

long x = 10000L * 4096L;
unsigned long long y = 1ULL << 36;

両方の例で、接尾辞なしで、定数はint型を持ち、計算はintとして行われます。各例では、オーバーフローのリスクが発生します。接尾辞を使用するということは、結果に対して十分な範囲がある代わりに、より大きな型で計算が行われることを意味します。

OrbitのLightness Racesが言うように、リタラルの接尾辞は割り当ての前にが付きます。上記の2つの例では、xlongとして宣言し、yunsigned long longとして宣言するだけでは、それらに割り当てられた式の計算のオーバーフローを防ぐのに十分ではありません。 。


別の例は、変数xの型がintである比較x < 12Uです。 U接尾辞がない場合、コンパイラは12intとして入力するため、比較は符号付き整数の比較になります。

int x = -3;
printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12

U接尾辞を使用すると、比較は符号なし整数の比較になります。 「通常の算術変換」とは、-3が大きな符号なし整数に変換されることを意味します。

printf("%d\n", x < 12U); // prints 0 because (unsigned int)-3 is large

実際、定数の型は、「通常の算術変換」の仕組みのために、算術計算の結果を変更することさえあります。


10進定数の場合、C99によって提案された型のリストにはunsigned long longが含まれないことに注意してください。 C90では、リストはその時点で最大の標準化された符号なし整数型(unsigned longでした)で終了しました。その結果、標準タイプlong longをC99に追加することで一部のプログラムの意味が変更されました。C90でunsigned longと入力されたのと同じ定数は、符号付きlong long代わりに。これが、C99でunsigned long longを10進定数の型のリストに含めないことを決定した理由だと思います。例については、 this および this のブログ投稿を参照してください。

58
Pascal Cuoq

数値リテラルは典型的にはint型であるためです。 UL/Lは、コンパイラにint型ではないことを伝えます。 32ビット整数と64ビット長を想定

long i = 0xffff;
long j = 0xffffUL;

ここでは、右側の値を符号付きlongに変換する必要があります(32ビット-> 64ビット)

  1. 「0xffff」、intは、符号拡張を使用してlongに変換され、負の値(0xffffffff)になります
  2. 「0xffffUL」、符号なしlongは、longに変換され、正の値(0x0000ffff)になります
9
codebauer

問題は、L/ULが長いと宣言した後でも、L/ULを長い定数で使用する必要がある理由です。

それは「後」ではないからです。それは「前」です。

最初に、リテラルがありますthenこれは、それを絞り込もうとしている変数の型に変換されます。

この投稿に関連するのは、uの理由です。

uの理由は、整数定数より大きいLLONG_MAXは10進数形式です。

// Likely to generate a warning.
unsigned long long limit63bit = 18446744073709551615`; // 2^64 - 1

// OK
unsigned long long limit63bit = 18446744073709551615u`;
0
chux