web-dev-qa-db-ja.com

i =(i、++ i、1)+ 1とは何ですか?行う?

未定義の動作とシーケンスポイントについて この回答 を読んだ後、小さなプログラムを作成しました。

#include <stdio.h>

int main(void) {
  int i = 5;
  i = (i, ++i, 1) + 1;
  printf("%d\n", i);
  return 0;
}

出力は2です。ああ、神様、私は減少が来るのを見なかった!ここで何が起きてるの?

また、上記のコードをコンパイルしているときに、次のような警告が表示されました。

px.c:5:8:警告:コンマ式の左側のオペランドは効果がありません

  [-Wunused-value]   i = (i, ++i, 1) + 1;
                        ^

どうして?しかし、おそらく私の最初の質問の答えによって自動的に答えられるでしょう。

173
gsamaras

(i, ++i, 1)では、使用されるコンマは コンマ演算子 です。

カンマ演算子(トークン,で表される)は、最初のオペランドを評価して結果を破棄し、2番目のオペランドを評価してこの値(および型)を返すバイナリ演算子です。

最初のオペランドを破棄するため、通常は、最初のオペランドに望ましい副作用がある場合にのみ有用です。第1オペランドへの副作用が発生しない場合、コンパイラーは、効果なしで式に関する警告を生成する場合があります。

したがって、上記の式では、左端のiが評価され、その値は破棄されます。次に、++iが評価され、iが1増加し、再び式++iの値が破棄されますが、iへの副作用は永続的です。その後、1が評価され、式の値は1になります。

それは同等です

i;          // Evaluate i and discard its value. This has no effect.
++i;        // Evaluate i and increment it by 1 and discard the value of expression ++i
i = 1 + 1;  

上記の式は完全に有効であり、未定義の動作を呼び出しません。これは、左と右の評価の間に シーケンスポイント があるためです。コンマ演算子のオペランド。

257
haccks

C11、章6.5.17カンマ演算子 から引用

コンマ演算子の左オペランドは、無効な式として評価されます。評価と右側のオペランドの評価の間にシーケンスポイントがあります。次に、右側のオペランドが評価されます。結果にはそのタイプと値があります。

だから、あなたの場合、

(i, ++i, 1)

として評価される

  1. i、void式として評価され、値は破棄されます
  2. ++i、void式として評価され、値は破棄されます
  3. 最後に、1、値が返されました。

したがって、最終的なステートメントは次のようになります

i = 1 + 1;

i2に到達します。これで両方の質問に答えられると思いますが、

  • iが値2を取得する方法
  • 警告メッセージがあるのはなぜですか?

注:FWIW、左側のオペランドの評価後にシーケンスポイントが存在するため、(i, ++i, 1)などの式は呼び出されませんUB、1つが一般的に誤って考える.

62
Sourav Ghosh
i = (i, ++i, 1) + 1;

段階的に分析してみましょう。

(i,   // is evaluated but ignored, there are other expressions after comma
++i,  // i is updated but the resulting value is ignored too
1)    // this value is finally used
+ 1   // 1 is added to the previous value 1

したがって、2を取得します。そして、最終的な割り当ては次のとおりです。

i = 2;

iにあったものはすべて、今では上書きされます。

30
dlask

の結果

(i, ++i, 1)

1

For

(i,++i,1) 

,演算子が評価された値を破棄し、1である右端の値のみを保持するように評価が行われます

そう

i = 1 + 1 = 2
19
Gopi

カンマ演算子 のwikiページでいくつかの優れた読書を見つけることができます。

基本的には、

...最初のオペランドを評価して結果を破棄し、2番目のオペランドを評価してこの値(および型)を返します。

この意味は

(i, i++, 1)

次に、iを評価し、結果を破棄し、i++を評価し、結果を破棄し、1を評価して返します。

14
Tomas Aschan

ここで、コンマ演算子が何をしているのかを知る必要があります。

あなたの表現:

(i, ++i, 1)

最初の式iが評価され、2番目の式++iが評価され、3番目の式1が式全体に対して返されます。

結果はi = 1 + 1です。

ボーナス質問については、ご覧のとおり、最初の式iはまったく効果がないため、コンパイラーは文句を言います。

13
songyuanyao

コンマの優先順位は「逆」です。これは、古い本やIBMのCマニュアル(70年代/ 80年代)から得られるものです。したがって、最後の「コマンド」は親式で使用されるものです。

現代のCでは、その使用は奇妙ですが、古いC(ANSI)では非常に興味深いものです。

do { 
    /* bla bla bla, consider conditional flow with several continue's */
} while ( prepAnything(), doSomethingElse(), logic_operation);

すべての操作(関数)は左から右に呼び出されますが、条件「while」の結果として最後の式のみが使用されます。これにより、条件チェックの前に実行するコマンドの一意のブロックを保持するための「goto」の処理が防止されます。

編集:これは、左オペランドのすべてのロジックを処理し、論理結果を返す可能性がある処理関数の呼び出しも回避します。 Cの過去にはインライン関数がなかったことを思い出してください。したがって、これにより呼び出しのオーバーヘッドを回避できます。

5
Luciano