例から
unsigned long x = 12345678UL
コンパイラは、上記の例で 4 バイト (32 ビット) のメモリを設定するために "long" のみを参照する必要があることを常に学びました。問題は、long であると宣言した後でも、long 定数で L/UL を使用する必要がある理由です。
接尾辞L
orUL
が使用されていない場合、コンパイラは、リストから定数を含むことができる最初の型を使用します (詳細については、C99 標準の 6.4.4:5 節を参照してください。10 進定数の場合、リストはint
, long int
, ですlong long int
)。
結果として、ほとんどの場合、接尾辞を使用する必要はありません。プログラムの意味は変わりません。. _ x
_ 接尾辞の一部が必要なlong long
例については、codebauer の回答も参照してください。U
プログラマーが定数の型を明示的に設定したい状況がいくつかあります。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
ます。各例で、これによりオーバーフローのリスクが発生します。接尾辞を使用すると、代わりに計算がより大きな型で行われ、結果の範囲が十分にあることを意味します。
Lightness Races in Orbit が言うように、リテラルの接尾辞は割り当ての前に来ます。x
上記の 2 つの例では、 aslong
とy
asを宣言するだけunsigned long long
では、割り当てられた式の計算でのオーバーフローを防ぐのに十分ではありません。
x < 12U
別の例は、 variablex
が typeである比較int
です。サフィックスがないU
場合、コンパイラは定数12
を としてint
型付けするため、比較は signed int の比較になります。
int x = -3;
printf("%d\n", x < 12); // prints 1 because it's true that -3 < 12
サフィックスを使用U
すると、比較は unsigned int の比較になります。「通常の算術変換」とは、-3 が大きな unsigned int に変換されることを意味します。
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
符号付きとして型指定できるようになりました。これが、C99で 10 進定数の型のリストにlong long
ないことが決定された理由だと思います。例については、これとこのブログ投稿をunsigned long long
参照してください。
数値リテラルは通常 int 型であるためです。UL/L は、int 型ではないことをコンパイラに伝えます。たとえば、32 ビットの int と 64 ビットの long を想定しています。
long i = 0xffff;
long j = 0xffffUL;
ここで、右側の値を符号付き long に変換する必要があります (32 ビット -> 64 ビット)。
問題は、long であると宣言した後でも、long 定数で L/UL を使用する必要がある理由です。
「後」ではないからです。「前」です。
最初にリテラルを取得し、それを絞り込もうとしている変数の型に変換されます。
それらは 2 つのオブジェクトです。unsigned long
あなたが言ったように、ターゲットのタイプはキーワードによって指定されます。リテラルの型を指定する唯一の方法であるため、ソースの型はこのサフィックスによって指定されます。