重複の可能性:
C /C++で整数のオーバーフローを検出するための最良の方法
私はインタビューでこの質問をされました:「数の文字列表現を整数に変換する」。ただし、その数が32ビット整数に格納できる最大値を超える場合は、エラーをスローする必要があります。私の質問は、数値が32ビットのunsignedintをオーバーフローするかどうかをどのように確認できるかということです。
重複の可能性:
C /C++で整数のオーバーフローを検出するための最良の方法
私はインタビューでこの質問をされました:「数の文字列表現を整数に変換する」。ただし、その数が32ビット整数に格納できる最大値を超える場合は、エラーをスローする必要があります。私の質問は、数値が32ビットのunsignedintをオーバーフローするかどうかをどのように確認できるかということです。
ループでは、最初の桁によって決定される整数の現在の値を取得しています。あなたがやろうとしていること:
curval = curval * 10 + digit; // digit converted from '0'..'9' to 0..9 already
次の方法でオーバーフローをテストできます。
if (curval > UINT32_MAX / 10 || (curval == UINT32_MAX / 10 && digit > UINT32_MAX % 10))
...overflow would occur...
else
curval = curval * 10 + digit; // overflow did not occur
除算と剰余演算はコンパイル時の演算であり、実行時の演算ではありません。
「計算に 32 ビットより大きい符号なし整数」を使用する場合よりもこのアプローチの利点の 1 つはuintmax_t
、定数を UINT32_MAX から UINT64_MAX または UINTMAX_MAX に変更することで、より大きな整数 (64 ビット整数と整数)で動作するように拡張できることです。 . 必要なのはこれだけです (もちろん、変数の型を変更する以外は)。
署名された型に対しても同じ基本的なテストが機能しますが、さらに複雑になります。デモ用に 16 ビット整数を使用する方が簡単です (入力して考える桁数が少ない)。そのため、次のように 16 ビットの 2 の補数に切り替えてshort
います。
USHRT_MAX
= 65535SHRT_MAX
= 32767SHRT_MIN
= -32768問題は、short
型が -32768 を格納できるが、累積できる最大の正の値が 32767 であることです。SHRT_MIN を除くすべての値について、上記のテストは正常に機能します。このジレンマを回避する方法があります。curval
1 つは、計算中に を負の値として格納し、正の値である必要がある場合は返す前に負にすることです。次に、テストは次のようになります。
if (curval < SHRT_MIN / 10 || (curval == SHRT_MIN / 10 && digit > -(SHRT_MIN / 10))
...overflow would occur...
else
curval = curval * 10 - digit; // Note subtraction!
負の値を否定する前に、curval
そうでないことを確認する必要があります。SHRT_MIN
(理論的には-SHRT_MAX != SHRT_MIN
、2 の補数バイナリ以外のシステムを許可するために、それを確認する必要があります。制限について引用した値はその条件を満たしています。)
もちろん、同じ考え方と手法がINT_MAX
、INT32_MAX
、INT64_MAX
およびINTMAX_MAX
に適用されます。
(私はこの質問の重複の可能性を調べましたが、面接の文脈では一般的なアイデア/アプローチを説明することが期待されるため、読むことがどれほど役立つかはわかりません)
面接の質問に答えることの一部は、明確な質問をすることです(面接官があなたに期待する重要なチェックリスト項目の1つ)。
したがって、問い合わせの行には、少なくとも次のようなものを含める必要があります。
unsigned long long
/ uint64_t
(64ビット整数)の使用は許可されていますか?stdin
/ファイルから読み取る/文字列リテラルとしてハードコードされていますか?あなたのインタビュアーがそれが小数表現であるとあなたに言うと仮定して+あなたは使うことができますunsigned long long
:
unsigned int
範囲は0 to 4,294,967,295
。10進数での数値の文字列表現が10文字を超える(10桁を超える)場合、すでにオーバーフローしています。エラーを発生させます。unsigned long long
で除算しUINT32_MAX+1=4294967296
ます。結果が、より大きい場合0
、オーバーフローします。エラーを発生させます。を使用して変換を行いuint64_t
ます。一度に 1 桁ずつ追加します。数字ごとに 10 を掛けて、次の文字の値を加算します。各文字を処理した後、結果が より大きいかどうかを確認しますUINT32_MAX
。そうである場合は、エラーで終了します (または、オーバーフロー時に行うべきことは何でも)。完了したら、数値を として返しますuint32_t
。uint64_t
、uint32_t
およびUINT32_MAX
で定義されていstdint.h
ます。