web-dev-qa-db-ja.com

Cでint / _Boolを切り替える方法

intがあり、それを01の間でブール式に切り替えたいとします。私は次の可能性を考えました:

int value = 0; // May as well be 1

value = value == 0 ? 1 : 0;
value = (value + 1) % 2;
value = !value; // I was curious if that would do...
  1. 3つ目は動作するようです。どうして? !01であると誰が決めるのですか?
  2. これらのいずれかに問題がありますか?
  3. 他の可能性はありますか?例えばビット演算子?
  4. どちらが最高のパフォーマンスを提供しますか?
  5. _Bool(またはstdbool.hのbool)と同じですか?そうでない場合、違いは何ですか?

編集:たくさんの貴重な情報を含む多くの素晴らしい答え、ありがとう!残念ながら、私は1つしか受け入れることができません。

16
riha

value = !value;は、直接実行したいことを表し、定義により、実行したいことを正確に実行します。

その表現を使用します。

C99 6.5.3.3/5「単項算術演算子」から:

論理否定演算子の結果です!オペランドの値が0と等しくない場合は0、オペランドの値が0と等しい場合は1。結果の型はintです。式!Eは(0 == E)と同等です。

28
Michael Burr

3つ目は動作するようです。どうして? !0が1だと誰が決めるのですか?

C標準では、!01であることを保証しています。

他の可能性はありますか?例えばビット演算子?

はい、排他的なOR演算子を使用できます:

value ^= 1;

ところで、私はこれをvalue = !value;よりも好んでいます。なぜなら、関係演算子と等価演算子は分岐につながる可能性があり、ビットごとの演算子は通常そうではないためです。

10
ouah
  1. 言語はそのように設計されました。
  2. 3番目のものを使用します。他のものは正しいですが、不必要に複雑であるため、意図を隠します。
  3. value = (value ^ 1) & 1;
  4. 最適化後もすべて同じです。
  5. _Boolも同じ結果になります。 _Boolとの唯一の違いは、値が1または0に強制的に変換されることです。つまり、bool x = 55;の値はx == 1

編集:私の頭痛のために3の式を修正しました。コメントを書いてもらい、私のブーパーを見てもらいました。

4

value = !valueが最も妥当な方法のようですが、value = 1 - valueまたはvalue ^= 1を使用することもできます。ただし、value0または1でない場合、最後の2つは両方とも壊れます。最初のものはまだ機能します。

3
detunized
value = 1 - value; // toggle from 0 to 1 ... or 1 to 0
                   // when you know initial value is either 0 or 1
3
Scott Stensland

アーキテクチャによっては、代替案で顕著なパフォーマンスの問題が発生する可能性があります。

  • !aは、一部のアーキテクチャでは比較と分岐が必要になる場合があります。これは、「a」のパターンによっては高価になる場合があります
    • 一部のアーキテクチャでは条件付きの移動(ブランチなし)がありますが、
      完了するにはまだ3つの指示が必要な場合があります(依存関係あり)
  • 1-aは多くのアーキテクチャで2つの命令を必要とする可能性が最も高い
    • カウンターの例:ARMには逆減算があります[〜#〜] rsb [〜#〜]%r0、%r0、#1
  • 1 ^ aは単一の命令で多くのアーキテクチャに実装できます
  • a =(a + 1)%2は、おそらく2つの命令を必要とするa =(a + 1)&1に最適化されます

しかし、とにかく最適化の最初のルールは、機能していないコードを最適化しないことです。 !aをa ^ 1に置き換えるには、常に期待値を生成することを100%確実にする必要があります。

3
Aki Suihkonen

式_value = value == 0 ? 1 : 0;_は、_value = !value;_とまったく同じように機能します。 2つのうちいずれかを使用できます。

_!0_は常に_1_であり、!(any non zero value)は_0_でもあります

1
CCoder

C#では、Math.Abs(value -1)を使用して、整数として0と1を切り替えることができます。

0
tkerwood