9

重複の可能性:
幅の広い整数に代入するときの C 整数オーバーフローの動作

グーグルでこれに関する明確な答えが見つかりませんでした。次の 2 つの式があるとします。

int16_t a16 = 100;
int16_t b16 = 2000;
int16_t result16 = (a16 * b16) / a16;

int8_t a8 = 100;
int8_t b8 = 20;
int8_t result8 = (a8* b8) / a8;

(a16 * b16) / a16and を評価するとき(a8 * b8) / a8、それらは評価中に常に昇格さintれ、最終結果は代入の直前に目的の型 (int16_tまたは) に変換されますか、それともこの整数昇格は完全にオプションですか? int8_t整数式の評価中の整数昇格は常に行われますか、それとも単純に許可されますか?

常に行われている場合、2 つの操作がオーバーフローしないことが期待できます ( int32 ビットであると仮定します)。実行のみが許可されている (必須ではない) 場合、操作がオーバーフローする可能性があります。挙動をよく知りたいです。

4

3 に答える 3

6
int16_t result16 = (a16 * b16) / a16;
int8_t result8 = (a8* b8) / a8;

これらの宣言は、次のものと同じです。

int16_t result16 = (int16_t) ((int) a16 * (int) b16) / (int) a16);
int8_t result8 = (int8_t) ((int) a8 * (int) b8) / (int) a8);

準拠する実装では、整数の昇格が必要です。一部の組み込みコンパイラは、コード密度を高めるためにデフォルトで整数昇格を実行しません (例: MPLAB C18 コンパイラ) が、これらのコンパイラは通常、準拠するANSIモードも持っています。

ここで、C の動作は、最適化の問題が関係ない抽象的なマシンの観点から記述されます。コンパイラーが整数の昇格を実行せずにプログラムに対して同じ観察可能な動作を達成できる場合、それを実行しなくてもかまいません。

intあなたが32ビットであると仮定すると、あなたは正しいです、この式:(a16 * b16) / a16オーバーフローすることはできません.

于 2012-10-09T20:37:53.493 に答える
4

まず、整数プロモーション6.3.1.1/2 があります。脚注 58 は次のように述べています。

整数昇格は、通常の算術変換の一部として、特定の引数式、単項 +、-、および ~ 演算子のオペランド、およびシフト演算子の両方のオペランドに、それぞれの節で指定されているようにのみ適用されます。

次に、通常の算術変換(6.3.1.8) があります。

[T]整数昇格は両方のオペランドで実行されます。次に、プロモートされたオペランドに次の規則が適用されます。

  • 両方のオペランドが同じ型の場合、それ以上の変換は必要ありません。

最後に、演算子があります。たとえば、乗算は次のように言います (6.5.5):

オペランドに対して通常の算術変換が実行されます。

したがって、式a8 * b8では、両方のオペランドがint整数の昇格によって昇格され、「それ以上の変換は必要ない」ため、式の結果にも型intがあります。

于 2012-10-09T20:46:20.543 に答える
2

結果が整数プロモーションを使用した場合とまったく同じである場合は、整数プロモーションを実行する必要はありません (これは as-if ルールのインスタンスです。規格が規定する方法と区別できない)。

算術演算子の仕様 (6.5.5、6.5.6) では、オペランドに対して整数昇格が実行されるため、「as if」に依存することができます。

ただし、操作自体が 16 ビットしかない可能性があるため、int16_t操作がオーバーフローしないことを完全に確信することはできません。int

于 2012-10-09T20:38:02.407 に答える