質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.10%

&&の条件文について。

解決済

回答 5

投稿

  • 評価
  • クリップ 2
  • VIEW 1,906

PaperZ

score 1

前提・実現したいこと

if (Move > 0 && ++Move > 40) のMove > 0 && ++Move > 40の部分について質問です。
Moveが毎回+1されるとしてMove > 0 により+1されていくとします。ですが&&よりMove自体は40より小さいため
++Move > 40を満たしていないため+1されないと思うのですが、なぜか正しく+1されます。
要はMoveの初期値は0より大きいが40より大きくないため++Move > 40の条件は満たさないのに
なぜちゃんと動いたのかわかりません。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

int Move = 1;
if (Move > 0 && ++Move > 40) {
                Move = 0; 
         A=10;
            }

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • PaperZ

    2019/09/26 19:28

    なるほど、優先順位ですね!
    ありがとうございました。

    キャンセル

  • Kapustin

    2019/09/27 00:11

    ちょっと本筋と外れるかもしれませんが、、「Moveが毎回+1されるとして」
    ここに少し違和感を感じました。該当のソースコードにはループ処理が発生するようなものはないので、for文やwhile文が別にあるのでしょうか。

    キャンセル

  • PaperZ

    2019/10/10 19:25

    えと、ループはあります。while文の中にif文を書いています。
    while文のことを書かなくてすいません。

    キャンセル

回答 5

checkベストアンサー

+7

コメントを受けて追記
if文を分けて全く同じ動作のコードにしてみた。
これでもわからなかったら具体的にどこがわからないか質問に追記ください。

if (Move > 0) {
    Move=Move+1;
    if (Move > 40) {
        Move = 0; 
        A=10;
    }
}


2019/10/10 補足として追記
それぞれのソースから同じアセンブリコードが生成されることを確認
※Win10 1803 WSLにてgcc を使用

$ # 元のソース
$ cat -n main.c
     1  #include <stdio.h>
     2
     3  void main(void){
     4          int Move=1;
     5          int A;
     6          if (Move > 0 && ++Move > 40) {
     7                  Move = 0;
     8                  A=10;
     9          }
    10  }
$ # if文を分解したソース
$ cat -n main2.c
     1  #include <stdio.h>
     2  void main(void){
     3          int Move=1;
     4          int A;
     5          if (Move > 0) {
     6                  Move=Move+1;
     7                  if (Move > 40) {
     8                          Move = 0;
     9                          A=10;
    10                  }
    11          }
    12  }
  • それぞれコンパイルしアセンブリコードを生成
$ gcc -S main.c
$ ll main.s
-rw-rw-rw- 1 root  root  498 1010 09:19 main.s
$ gcc -S main2.c
$ ll main2.s
-rw-rw-rw- 1 root  root  499 1010 09:19 main2.s
  • アセンブリコード - 元のソース
$ cat -n main.s
     1          .file   "main.c"
     2          .text
     3          .globl  main
     4          .type   main, @function
     5  main:
     6  .LFB0:
     7          .cfi_startproc
     8          pushq   %rbp
     9          .cfi_def_cfa_offset 16
    10          .cfi_offset 6, -16
    11          movq    %rsp, %rbp
    12          .cfi_def_cfa_register 6
    13          movl    $1, -8(%rbp)
    14          cmpl    $0, -8(%rbp)
    15          jle     .L3
    16          addl    $1, -8(%rbp)
    17          cmpl    $40, -8(%rbp)
    18          jle     .L3
    19          movl    $0, -8(%rbp)
    20          movl    $10, -4(%rbp)
    21  .L3:
    22          nop
    23          popq    %rbp
    24          .cfi_def_cfa 7, 8
    25          ret
    26          .cfi_endproc
    27  .LFE0:
    28          .size   main, .-main
    29          .ident  "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
    30          .section        .note.GNU-stack,"",@progbits
  • アセンブリコード - if文を分解したソース
$ cat -n main2.s
     1          .file   "main2.c"
     2          .text
     3          .globl  main
     4          .type   main, @function
     5  main:
     6  .LFB0:
     7          .cfi_startproc
     8          pushq   %rbp
     9          .cfi_def_cfa_offset 16
    10          .cfi_offset 6, -16
    11          movq    %rsp, %rbp
    12          .cfi_def_cfa_register 6
    13          movl    $1, -8(%rbp)
    14          cmpl    $0, -8(%rbp)
    15          jle     .L3
    16          addl    $1, -8(%rbp)
    17          cmpl    $40, -8(%rbp)
    18          jle     .L3
    19          movl    $0, -8(%rbp)
    20          movl    $10, -4(%rbp)
    21  .L3:
    22          nop
    23          popq    %rbp
    24          .cfi_def_cfa 7, 8
    25          ret
    26          .cfi_endproc
    27  .LFE0:
    28          .size   main, .-main
    29          .ident  "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
    30          .section        .note.GNU-stack,"",@progbits
  • アセンブリコードを比較
$ diff main.s main2.s
1c1
<       .file   "main.c"
---
>       .file   "main2.c"
$ 

コメント入れてみた。
これでもわからなかったら具体的にどこがわからないか質問に追記ください。

if (Move > 0) {
    Move=Move+1;
    if (Move > 40) {
        Move = 0; 
      A=10;
    }
}
// Move1を入れる
int Move = 1;

// もし ((Move0より大きい) かつ (まずMove1足す。足した後の Move40より大きい)) なら
if (Move > 0 && ++Move > 40) {
    // Move0を入れる
    Move = 0; 
    // Aに10を入れる
  A=10;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/10 16:27 編集

    Y.Hさんは、どのように勉強されたことで if (Move > 0 && ++Move > 40)が
    if (Move > 0) {
    Move=Move+1;
    if (Move > 40) {
    Move = 0;

    の順番で働くとわかったのでしょうか。

    キャンセル

  • 2019/10/10 16:43

    単純に以下のように分解しただけですよ。

    if ( (Move > 0) && ( (++Move) > 40) ) {Move = 0;}

    if (Move > 0) { if ( (++Move) > 40) {Move = 0;} }

    if (Move > 0) { Move=Move+1; if ( Move > 40) {Move = 0;} }

    キャンセル

  • 2019/10/10 16:51

    こんな私でもやっと理解できました。わかりやすい解説ありがとうございます。

    キャンセル

+5

ですが&&よりMove自体は40より小さいため
++Move > 40を満たしていないため+1されないと思うのですが、なぜか正しく+1されます。

「++Move > 40を満たしていないため+1されない」が間違いだから。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/27 16:35

    ↑それな。

    じゃーなにかい、f(x)==0 は、f(x)が0じゃなかったら関数fを呼ばなかったことにしてくれると信じてるのかい?

    キャンセル

  • 2019/09/27 16:48

    ってことは、優先的にMoveの値をインクリメントして、次に(0より大きく)40より大きいか評価され、最後は((0より大きく)40より大きいか評価された後で)&&によりどちらの条件も真のときに{}に書いたことを実行するということですね。

    キャンセル

  • 2019/09/27 17:00

    書いたとおりに動く。そんだけ。

    キャンセル

+3

++Move > 40

これが評価される時点でインクリメントされます
結果がどーこーは関係ありません

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/26 19:02

    Move > 0 が偽であれば、&&の右側は評価されません。
    なにか勘違いしてませんか?

    キャンセル

  • 2019/09/26 20:14

    要は優先順位が大事なのですね。

    キャンセル

  • 2019/10/10 10:01

    優先順位ではない。&&の短絡評価だ。

    キャンセル

+3

式がどのように評価されるのかまとめてみました。
評価

評価(evaluation)それ自体の意味、Cは基本的に先行評価(正格評価とも言われる)であるが、&&||?:のみ遅延評価(短絡評価とも言われる)があること、これらを理解しないとCを書くことは難しいです。他にもインクリメント・デクリメントは副作用と評価値の関係を正確に理解していないと使いこなすことは不可能です。さらに深く理解するには左辺値と右辺値の関係が重要になっていきます。Cの場合はある程度曖昧でもなんとかなってしまう場合もありますが、C++ではより厳密性が増すため、まともなコードを書くことも理解することも無理でしょう。

なお、評価の傍線が並列になっているところは順不定です。Cの仕様上、どちらが先になるかは定まらないとなっています。


【追記】なぜ、左辺値や遅延評価などの言葉を使っているのか?

左辺値や遅延評価などの言葉を知らないと理解ができないからではなく、左辺値や遅延評価などが理解できないとこの式を理解することはできないと私は考えるからです。言葉を知らなければ調べれば良いだけですので、知っているかどうかは重要でありません。しかし、この式を真に理解するには、左辺値や遅延評価というものをある程度の理解できなければ不可能と考えています。もし、理解できるほとどにCがわかっているのであれば、あとは言葉の意味を調べれば良いだけですし、それらも理解できるはずです。理解できなければ、Cそのものというよりプログラミングというものそのものに対して学習が不足していると思います。そのような状態では、いくらどれだけ言葉を重ねても、理解することは不可能でしょう。

ぶっちゃけ、この質問への回答はY.H.さんが最初に書いた素晴らしいコードで十分と思っていました。同等であるコードが理解できれば、元々のコードがそうなることは理解できるからです。Y.H.さんの素晴らしいコードであれば左辺値や遅延評価などを理解することができないレベルでも理解することができるでしょう。

ただ、私としては、「同等である」ということを理解するには、結局&&++の性質につてより良く理解しておく必要があり、やはり、左辺値なり、遅延評価なりを理解できるレベルではないと、難しいと思っています。ここに一つの壁があると言うことです。この同等のコードを書くことは、単純に置き換えるように見えますが、そうではありません。例えば条件部分がMove > 0 && Move++ > 40だった場合、少し違ったコードになります。結局の所、「なぜ同等なのか」への理解を曖昧なまま進めても、また同じ問題にぶつかるだけだと思います。

もし、私の回答で混乱としたと感じた人がいましたら、私は「あなたはCの複雑なコードを書くレベルにも読むレベルにも達していない」と言いたいです。そのような人達に対する私のアドバイスとしては次の何れかに従うことです。

  1. C以外の言語、とくにプログラミング初学者を意識して作られた言語からプログラミングを始めることをお勧めします。一番のお勧めはPythonです。Pythonは複雑な書き方ができず(全くできないわけでは無いが、非常に書きにくくなっている)、また、インデントも綺麗に揃えることを強制し、書く側も読む側も大変わかりやすい言語です。それにもかかわらず、様々な分野で実用的なアプリケーションの開発に使われており、身につけておいて損にはなりません。

  2. どうしてもCにこだわるのであれば、自分が理解できる範囲でコードを一から作ることをお勧めします。++は使わない、&&はifで表現する、または、左右は変数一つのみにして単純化する、といったことをしてください。一つの文で複数のことを行おうとはしないでください。言ってみれば、Y.H.さんのコードのような形です。プログラミングとは自分が理解できるコードを自分で書くことです。他人が書いたコードを切り貼りすることはプログラミングとは言えません。

なお、私が開発者で同じことを実装するのであれば、Y.H.さんのコードのように書きます。中身を理解できても、ぱっと見でわからなければ、それは私にとって価値が無いコードだからです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/15 11:39 編集

    個人で連絡を取れるなら普通は個人で連絡を取るからです。身分を明かしてどの発言かを確定し、それで万一間違っていたら episteme さんが自分で訂正されるでしょう。
    その発言がこの場でなされたものでない以上、ここで言う意味はありません。一般に、間違った発言は、それを見聞きした人にだけ訂正されれば十分です。
    もっとも私は、今までの経緯から、carnage0216 さん改め DR.Dexter00 さん改め PaperZ さんの読み違い、聞き違いの可能性が高いと思っています。

    キャンセル

  • 2019/10/15 11:54

    わかりました。

    キャンセル

  • 2019/10/15 11:59 編集

    では「epistemeさん、あなたの考えは間違っています...」は撤回てことで。
    ※ 消しといてくれるとありがたい

    キャンセル

-2

優先順位の問題です。
++>より先に評価され、>&&より先に評価されます。

括弧で順位を明示するならば

((Move > 0) && ((++Move) > 40))


括弧の有無に関わらず、Moveが0より大きいならばまずインクリメント、次に比較、最後に論理積です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/27 12:29

    優先順位の問題ではないことは説明したし、そのほか丁寧に説明したつもりです。それでも結論が「ぼかさなかったから」になるのであれば、もう何も言えることはありません。

    キャンセル

  • 2019/09/27 15:53 編集

    > 関数の引数を評価する前に関数に値を渡すことと同義かと。

    いえ、違います。関数呼び出しは副作用完了点ですが、&&、||、? :を除いた演算子の評価はそうではありません。

    https://www.jpcert.or.jp/sc-rules/c-exp30-c.html

    キャンセル

  • 2019/09/27 17:51

    この回答の意味は
    「++Move > 40 は ++(Move > 40) ではないぞ」ということ?
    だとしたら質問と噛み合わないような…?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る