1. ホーム
  2. c

[解決済み] C言語での符号→符号なし変換 - 常に安全か?

2022-04-29 01:04:08

質問

次のようなC言語コードがあるとします。

unsigned int u = 1234;
int i = -5678;

unsigned int result = u + i;

ここでどのような暗黙の変換が行われているのか、また、このコードは ui ? (安全という意味で、たとえ 結果 この例では、正の巨大な数にオーバーフローしてしまいますが、それを int で、本当の結果を得ることができます)。

どのように解決するのですか?

簡単な答え

あなたの i は、次のようになります。 変換済み を追加して符号なし整数に変換します。 UINT_MAX + 1 の場合、符号なし値で加算が行われ、結果として大きな result (の値によって異なります)。 ui ).

長い回答

C99規格による。

6.3.1.8 通常の算術変換

  1. もし両方のオペランドが同じ型であれば、それ以上の変換は必要ない。
  2. そうでない場合、オペランドが両方とも符号付き整数型であるか、両方とも符号なし整数型であれば、整数変換順位の小さい方のオペランドの型が大きい方のオペランドの型に変換されます。
  3. それ以外の場合、符号なし整数型を持つオペランドのランクがもう一方のオペランドの型のランク以上であれば、符号あり整数型を持つオペランドは符号なし整数型を持つオペランドの型に変換されます。
  4. それ以外の場合、符号付き整数型のオペランドの型が符号なし整数型のオペランドの型のすべての値を表すことができるならば、符号なし整数型のオペランドは符号付き整数型のオペランドの型に変換されます。
  5. そうでない場合は、両方のオペランドが符号付き整数型のオペランドの型に対応する符号なし整数型に変換されます。

あなたの場合、1つのunsigned int()があります。 u ) と符号付き int ( i ). 上記(3)を参照すると、両オペランドは同じランクであるため、あなたの i にする必要があります。 変換 を符号なし整数に変換します。

6.3.1.3 符号付き整数と符号なし整数

  1. 整数型の値を _Bool 以外の整数型に変換したとき、その値が新しい型で表現できるのであれば、その値は変更されない。
  2. そうでない場合、新しい型が unsigned であれば、値が新しい型の範囲に入るまで、新しい型で表現できる最大値よりも1つ多く加算または減算を繰り返して変換されます。
  3. それ以外の場合、新しい型は符号付きで、値を表すことができません。結果は実装で定義されるか、実装で定義されたシグナルが発生します。

ここで、上記(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を使用しても安全ですか?