[解決済み] C言語での符号→符号なし変換 - 常に安全か?
質問
次のようなC言語コードがあるとします。
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
ここでどのような暗黙の変換が行われているのか、また、このコードは
u
と
i
? (安全という意味で、たとえ
結果
この例では、正の巨大な数にオーバーフローしてしまいますが、それを
int
で、本当の結果を得ることができます)。
どのように解決するのですか?
簡単な答え
あなたの
i
は、次のようになります。
変換済み
を追加して符号なし整数に変換します。
UINT_MAX + 1
の場合、符号なし値で加算が行われ、結果として大きな
result
(の値によって異なります)。
u
と
i
).
長い回答
C99規格による。
6.3.1.8 通常の算術変換
- もし両方のオペランドが同じ型であれば、それ以上の変換は必要ない。
- そうでない場合、オペランドが両方とも符号付き整数型であるか、両方とも符号なし整数型であれば、整数変換順位の小さい方のオペランドの型が大きい方のオペランドの型に変換されます。
- それ以外の場合、符号なし整数型を持つオペランドのランクがもう一方のオペランドの型のランク以上であれば、符号あり整数型を持つオペランドは符号なし整数型を持つオペランドの型に変換されます。
- それ以外の場合、符号付き整数型のオペランドの型が符号なし整数型のオペランドの型のすべての値を表すことができるならば、符号なし整数型のオペランドは符号付き整数型のオペランドの型に変換されます。
- そうでない場合は、両方のオペランドが符号付き整数型のオペランドの型に対応する符号なし整数型に変換されます。
あなたの場合、1つのunsigned int()があります。
u
) と符号付き int (
i
). 上記(3)を参照すると、両オペランドは同じランクであるため、あなたの
i
にする必要があります。
変換
を符号なし整数に変換します。
6.3.1.3 符号付き整数と符号なし整数
- 整数型の値を _Bool 以外の整数型に変換したとき、その値が新しい型で表現できるのであれば、その値は変更されない。
- そうでない場合、新しい型が unsigned であれば、値が新しい型の範囲に入るまで、新しい型で表現できる最大値よりも1つ多く加算または減算を繰り返して変換されます。
- それ以外の場合、新しい型は符号付きで、値を表すことができません。結果は実装で定義されるか、実装で定義されたシグナルが発生します。
ここで、上記(2)を参照する必要があります。あなたの
i
を追加することで、符号なし値に変換されます。
UINT_MAX + 1
. したがって、結果は
UINT_MAX
は、あなたの実装で定義されています。大きくはなりますが、オーバーフローはしませんので。
6.2.5 (9)
符号なしオペランドを含む計算では、結果の符号なし整数型で表現できない結果は、結果の型で表現できる最大の値より1大きい数で減少するため、決してオーバーフローすることはありません。
ボーナス:算術変換準WTF
#include <stdio.h>
int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;
if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");
return 0;
}
このリンクからオンラインで試すことができます。 https://repl.it/repls/QuickWhimsicalBytes
ボーナス:算術変換の副作用
算術変換規則で
UINT_MAX
に符号なし値を初期化することで
-1
, すなわち
unsigned int umax = -1; // umax set to UINT_MAX
これは、上記の変換規則により、システムの符号付き数値表現に関係なく移植性が保証されています。詳しくはこのSOの質問を参照してください。 すべてのビットを真にするために-1を使用しても安全ですか?
関連
-
赤線の位置は必ずしも間違っていない:式は変更可能なlvalueでなければならないエラーは、この文とは別の場所に存在する可能性があります。
-
警告:代入がキャストなしで整数からポインタを作成する場合の修正方法に関する警告
-
initializer element is not constant "というエラーが表示されるのですが?
-
[解決済み] mallocで文字列を確保する
-
[解決済み] C言語でchar配列をコピーする方法は?
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
-
[解決済み] C言語標準に準拠した構造体の初期化方法
-
[解決済み] ストラクチャーとユニオンの違い
-
[解決済み】符号なし整数のオーバーフローは定義されているのに、符号あり整数のオーバーフローは定義されていないのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
libc++abi.dylib: NSException タイプの捕捉されない例外で終了するエラー
-
[C] Error [Error] 代入の左オペランドとして lvalue が必要です。
-
警告:代入がキャストなしで整数からポインタを作成する場合の修正方法に関する警告
-
C 言語のポインタ配列のポインタ型、ポインタに値を割り当てるために配列名を使用、コンパイル時の警告:互換性のないポインタ型からの初期化
-
[解決済み] C言語でchar配列をコピーする方法は?
-
[解決済み] Cプリプロセッサはなぜ "linux "という単語を定数 "1 "と解釈するのですか?
-
[解決済み] C言語でランダムなint型を生成するには?
-
[解決済み] C言語のi++と++iに性能差はあるのでしょうか?
-
[解決済み] .aファイル、.soファイルとは何ですか?
-
[解決済み] すべてのビットを真にするために-1を使用しても安全ですか?