web-dev-qa-db-ja.com

Cでlong intをintに割り当てるとどうなりますか?

最近の宿題では、long変数を使用して結果を保存するように言われました。

私のシステム(インテルコアi5/64ビットWindows 7/gnu gccコンパイラー)で、私にとって本当に重要かどうかを確認することにし、次のコードを見つけました。

printf("sizeof(char) => %d\n", sizeof(char));
printf("sizeof(short) => %d\n", sizeof(short));
printf("sizeof(short int) => %d\n", sizeof(short int));
printf("sizeof(int) => %d\n", sizeof(int));
printf("sizeof(long) => %d\n", sizeof(long));
printf("sizeof(long int) => %d\n", sizeof(long int));
printf("sizeof(long long) => %d\n", sizeof(long long));
printf("sizeof(long long int) => %d\n", sizeof(long long int));

次の出力が生成されます。

sizeof(char) => 1
sizeof(short) => 2
sizeof(short int) => 2
sizeof(int) => 4
sizeof(long) => 4
sizeof(long int) => 4
sizeof(long long) => 8
sizeof(long long int) => 8

言い換えると、私のシステムでは、intlongは同じであり、intが保持するには大きすぎるものはlongも保持します。

ここでは宿題の割り当て自体は問題ではありません。どのように、システム上で_int < longintをlongに割り当てる必要がありますか?

あるある多数の近い関連する の質問この主題ですが、これらの答えは、プロセスの中で何が起こるか、または起こるかもしれないかについての完全な理解を私に提供しないと思います。

基本的に私は次のことを理解しようとしています:

  1. 割り当て前にlongintにキャストするか、または longは異なるデータ型ではなく、単なる修飾子であるため、 直接割り当てることは無害と見なされますか?
  2. long > int?結果は未定義(または予測不能)になりますか、それとも変数の余分な部分が省略されますか?
  3. longからintへのキャストはCではどのように機能しますか?
  4. キャストを使用しない場合、Cではlongからintへの割り当てはどのように機能しますか?
54
Khaloymes

この言語は、intが少なくとも16ビット、longが少なくとも32ビット、およびlong少なくともを表すことができることを保証します。 intは表現できます。

long値をintオブジェクトに割り当てると、暗黙的に変換されます。明示的なキャストの必要はありません。とにかく起こる同じ変換を指定するだけです。

システムでは、intlongのサイズと範囲が同じ場合、変換は簡単です。値をコピーするだけです。

longintよりも広いシステムでは、値がintに収まらない場合、変換の結果は実装で定義されます。 (または、C99以降、実装定義のシグナルを生成できますが、実際にそれを行うコンパイラーは知りません。)通常が起こるのは、高位ビットが破棄されることです。 、しかしそれに依存するべきではありません。 (符号なしの型では規則が異なります。符号付きまたは符号なし整数を符号なしの型に変換した結果は明確に定義されています。)

安全にlong値をintオブジェクトに割り当てる必要がある場合は、割り当てを行う前に値が収まることを確認できます。

#include <limits.h> /* for INT_MIN, INT_MAX */

/* ... */

int i;
long li = /* whatever */

if (li >= INT_MIN && li <= INT_MAX) {
    i = li;
}
else {
    /* do something else? */
}

「他の何か」の詳細は、あなたが何をしたいかに依存します。

1つの修正:intlongは、同じサイズと表現を持っている場合でもalways別個のタイプです。算術型は自由に変換できるため、多くの場合、違いはありませんが、たとえばint*long*は明確で互換性のない型です。明示的な(および潜在的に危険な)キャストなしでは、long*int*に割り当てることはできません。

long値をintに変換する必要がある場合、最初にすべきことは、コードの設計を再検討することです。そのような変換が必要な場合もありますが、多くの場合、割り当てられているintが最初にlongとして定義されている必要があるという兆候です。

43
Keith Thompson

longは、常にintのすべての値を表すことができます。割り当てられた変数の型で手元の値を表すことができる場合、値は保持されます。

表現できない場合は、符号付き宛先タイプの場合、結果は形式的に指定されませんが、符号なし宛先タイプの場合は、2を法とする元の値として指定されますn、 どこ n 値表現のビット数です(宛先のすべてのビットとは限りません)。

実際には、最新のマシンでは、署名されたタイプのラッピングも行われます。

これは、最新のマシンが2の補数形式を使用して符号付き整数を表すためです。「無効な値」などを示すために使用されるビットはありません。

と n 任意の整数値のビット値表現 バツ にマップされます バツ+ K * 2n 結果が可能な値の半分が負になる範囲になるように整数定数Kを選択します。

したがって、たとえば、32ビットintでは、値-7はビットパターン番号-7 + 2として表されます32 = 232-7。ビットパターンが符号なし整数として表す数値を表示すると、かなり大きな数値が得られます。

これが2の補数と呼ばれる理由は、2進数の基数システムである2進数の数字システムにとって意味があるためです。 2進数システムの場合は、1の補数(アポストロフィの配置に注意)もあります。同様に、10進数システムでは、10の補数と9の補数があります。 4桁の10の補数表現では、-7は10000-7 = 9993として表されます。これですべてです。