49

例から

unsigned long x = 12345678UL

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

4

4 に答える 4

81

接尾辞LorULが使用されていない場合、コンパイラは、リストから定数を含むことができる最初の型を使用します (詳細については、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 つの例では、 aslongyasを宣言するだけ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参照してください。

于 2012-10-30T08:28:25.070 に答える
17

数値リテラルは通常 int 型であるためです。UL/L は、int 型ではないことをコンパイラに伝えます。たとえば、32 ビットの int と 64 ビットの long を想定しています。

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

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

  1. int である「0xffff」は、符号拡張を使用して long に変換され、負の値 (0xffffffff) になります。
  2. unsigned long の "0xffffUL" は long に変換され、正の値 (0x0000ffff) になります。
于 2012-10-30T08:40:25.847 に答える
10

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

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

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

それらは 2 つのオブジェクトです。unsigned longあなたが言ったように、ターゲットのタイプはキーワードによって指定されます。リテラルの型を指定する唯一の方法であるため、ソースの型はこのサフィックスによって指定されます。

于 2012-10-30T12:47:44.823 に答える