2013-03-27 8 views
11

C実装(例えば、x86 Cコンパイラ)の場合、USHRT_MAX = 65535INT_MAX = 2147483647とします。次のステートメントは明確に定義されていますか?オーバーフローが発生するので、従って、(intunsigned shortのすべての可能な値を表すことができるため)両方のオペランドがintに昇格されるC99標準で以下とによるintプロモーション:以下は明確に定義されていますか?

unsigned short product = USHRT_MAX * USHRT_MAX; 

は、結果は、十分に定義されていません( productの値が十分に定義されていないことを意味する65535^2 = 4294836225 > 2147483647):

6.3.1.1-1

int型のCA場合nは元の型のすべての値を表し、値は をintに変換したものです。それ以外の場合は、unsigned intに変換されます。 これは、整数プロモーションと呼ばれます。(48)他のすべてのタイプは整数プロモーションによって変更されずに です。

48)整数キャンペーンのみ適用されます、単項+の オペランドに、特定の引数の式に、通常 算術変換の一部として - 、および〜演算子、 シフトの両方のオペランドに事業者は、それぞれの副次節で指定されているとおりである。

符号なしオペランドを含む計算がオーバーフローしないので、以下に従って、結果は、明確に定義されている:

6.2.5-9

非負の範囲を符号付き整数型の値は対応する符号なし整数型のサブ範囲 であり、各型の同じ値の の表現は同じです。(31)を含む計算結果の符号なし整数型で表される の結果は、 の結果の型で表される最大値よりも1だけ大きい数値である を減じた値になるため、符号なしのオペランドはオーバーフローすることはありません。

上記の文で変数productは明確に定義された値を持っていますか?

EDIT:次の場合はどうなりますか?

unsigned short lhs = USHRT_MAX; 
unsigned short rhs = USHRT_MAX; 
unsigned short product = lhs * rhs; 
+2

モラル:算術演算に 'int'より小さい型を使用しないでください。ルールは人間の正しいコードを書けるようにあまりにも混乱します。 –

+0

2つのコードには違いはありません。 'int'へのプロモーションは、あなたが定数か変数かを問わずに発生します。 –

+2

ニットのように、最初のケースでは「int」への*プロモーション*はありません。指定された 'USHRT_MAX'は' int 'です。 '65535U'と宣言すれば全体の画像が変わるでしょう。 –

答えて

4

昇進が勝ちます。

は、以下に示す値は#if前処理指令で使用するのに適した定数式に置き換えなければならない定数約セクション5.2.4.2.1 USHRT_MAX等:

言います。さらに、CHAR_BITMB_LEN_MAXを除いて、次のは、整数昇格に従って変換された対応する型のオブジェクトである式と同じ型を持つ式に置き換えなければならない。

ので、乗算はintの上にあり、そして何の符号なしオペランドを伴わない、明確に、USHRT_MAX < INT_MAX場合は、符号なしのオペランドを伴う操作を取得するためにUSHRT_MAXを実装するいかなる準拠方法はありません。したがって、オーバーフローし、未定義の動作が発生します。追加質問

EDITについて

:何が次のような場合に起こるのでしょうか?まったく同じ状況です

unsigned short lhs = USHRT_MAX; 
unsigned short rhs = USHRT_MAX; 
unsigned short product = lhs * rhs; 

*のオペランドは整数キャンペーンの対象となり、タイプunsigned shortのすべての値は、USHRT_MAXINT_MAXの値に関する仮定によってint Sとして表すことができるので、乗算int S上で、指定された値でオーバーフローします。

少なくとも1つのオペランドを、符号なしタイプに変換する必要があります。このタイプの符号なしタイプは、符号なしのオペランドで乗算を実行する場合は、intに昇格されません。

1

あなたは時間によって乗算演算子が適用されているので、そのオペランドがすでに(なぜなら最初に発生intへのプロモーションの)符号付き整数であるUBを取得します。

あなたが仕事アラウンドできることをこれで:(unsigned)some_integerはとどまることを

unsigned short product = USHRT_MAX * (unsigned)USHRT_MAX; 

証明は、符号なし:

#include <stdio.h> 

int main(void) 
{ 
    printf("1u * (-1) = %f\n", (((unsigned)1) * (-1)) + 0.0); 
    printf("1 * (-1) = %f\n", (1 * (-1)) + 0.0); 
    return 0; 
} 

出力(ideone):

1u * (-1) = 4294967295.000000 
1 * (-1) = -1.000000 

グッドキャッチ、ところでを。

+0

これは動作しません。通常の算術変換によれば、「そうでなければ、符号付き整数型のオペランドの型が、符号なし整数型のオペランドの型のすべての値を表すことができる場合、符号なし整数型のオペランドは、符号付き整数型のオペランド。 "したがって、両方のオペランドが 'int'に昇格され、オーバーフローが発生します。 – Alexandros

+0

これは動作します。 'unsigned int'は魔法のように' signed int'に変換されません。とんでもない。アップデートを参照してください。 –

+0

@Alexandros: 'unsigned'は整数昇格(6.3.1.1/2、「int型またはunsigned int以外の整数型を持つオブジェクトまたは式)」の下で同じままであるため、動作します。 'USHRT_MAX'は' int'に変換されますが、 'unsigned'オペランドは' int'に変換されません。次に、「通常の算術変換」は乗算に 'unsigned'を選択します。 –

関連する問題