前提・実現したいこと
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/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/26 10:21
2019/09/26 10:28
2019/09/26 15:11
2019/10/10 10:25
回答5件
0
ベストアンサー
コメントを受けて追記
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 10月 10 09:19 main.s $ gcc -S main2.c $ ll main2.s -rw-rw-rw- 1 root root 499 10月 10 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; } }
// Moveに1を入れる int Move = 1; // もし ((Move が 0より大きい) かつ (まずMoveに1足す。足した後の Move が 40より大きい)) なら if (Move > 0 && ++Move > 40) { // Moveに0を入れる Move = 0; // Aに10を入れる A=10; }
投稿2019/09/26 09:18
編集2019/10/10 00:52総合スコア7918
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/26 09:24
2019/09/26 09:56
2019/10/09 22:21 編集
2019/10/10 00:44
2019/10/10 07:24
2019/10/10 07:28 編集
2019/10/10 07:43
2019/10/10 07:51
0
ですが&&よりMove自体は40より小さいため
++Move > 40を満たしていないため+1されないと思うのですが、なぜか正しく+1されます。
「++Move > 40を満たしていないため+1されない」が間違いだから。
投稿2019/09/26 10:18
総合スコア16612
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/26 10:28
2019/09/26 11:38
2019/09/27 01:40
2019/09/27 02:43
2019/09/27 06:44
2019/09/27 06:50
2019/09/27 07:01
2019/09/27 07:11
2019/09/27 07:15
2019/09/27 07:23
2019/09/27 07:26
2019/09/27 07:30
2019/09/27 07:35
2019/09/27 07:48
2019/09/27 08:00
0
評価(evaluation)それ自体の意味、Cは基本的に先行評価(正格評価とも言われる)であるが、&&
と||
と?:
のみ遅延評価(短絡評価とも言われる)があること、これらを理解しないとCを書くことは難しいです。他にもインクリメント・デクリメントは副作用と評価値の関係を正確に理解していないと使いこなすことは不可能です。さらに深く理解するには左辺値と右辺値の関係が重要になっていきます。Cの場合はある程度曖昧でもなんとかなってしまう場合もありますが、C++ではより厳密性が増すため、まともなコードを書くことも理解することも無理でしょう。
なお、評価の傍線が並列になっているところは順不定です。Cの仕様上、どちらが先になるかは定まらないとなっています。
【追記】なぜ、左辺値や遅延評価などの言葉を使っているのか?
左辺値や遅延評価などの言葉を知らないと理解ができないからではなく、左辺値や遅延評価などが理解できないとこの式を理解することはできないと私は考えるからです。言葉を知らなければ調べれば良いだけですので、知っているかどうかは重要でありません。しかし、この式を真に理解するには、左辺値や遅延評価というものをある程度の理解できなければ不可能と考えています。もし、理解できるほとどにCがわかっているのであれば、あとは言葉の意味を調べれば良いだけですし、それらも理解できるはずです。理解できなければ、Cそのものというよりプログラミングというものそのものに対して学習が不足していると思います。そのような状態では、いくらどれだけ言葉を重ねても、理解することは不可能でしょう。
ぶっちゃけ、この質問への回答はY.H.さんが最初に書いた素晴らしいコードで十分と思っていました。同等であるコードが理解できれば、元々のコードがそうなることは理解できるからです。Y.H.さんの素晴らしいコードであれば左辺値や遅延評価などを理解することができないレベルでも理解することができるでしょう。
ただ、私としては、「同等である」ということを理解するには、結局&&
や++
の性質につてより良く理解しておく必要があり、やはり、左辺値なり、遅延評価なりを理解できるレベルではないと、難しいと思っています。ここに一つの壁があると言うことです。この同等のコードを書くことは、単純に置き換えるように見えますが、そうではありません。例えば条件部分がMove > 0 && Move++ > 40
だった場合、少し違ったコードになります。結局の所、「なぜ同等なのか」への理解を曖昧なまま進めても、また同じ問題にぶつかるだけだと思います。
もし、私の回答で混乱としたと感じた人がいましたら、私は「あなたはCの複雑なコードを書くレベルにも読むレベルにも達していない」と言いたいです。そのような人達に対する私のアドバイスとしては次の何れかに従うことです。
-
C以外の言語、とくにプログラミング初学者を意識して作られた言語からプログラミングを始めることをお勧めします。一番のお勧めはPythonです。Pythonは複雑な書き方ができず(全くできないわけでは無いが、非常に書きにくくなっている)、また、インデントも綺麗に揃えることを強制し、書く側も読む側も大変わかりやすい言語です。それにもかかわらず、様々な分野で実用的なアプリケーションの開発に使われており、身につけておいて損にはなりません。
-
どうしてもCにこだわるのであれば、自分が理解できる範囲でコードを一から作ることをお勧めします。
++
は使わない、&&
はifで表現する、または、左右は変数一つのみにして単純化する、といったことをしてください。一つの文で複数のことを行おうとはしないでください。言ってみれば、Y.H.さんのコードのような形です。プログラミングとは自分が理解できるコードを自分で書くことです。他人が書いたコードを切り貼りすることはプログラミングとは言えません。
なお、私が開発者で同じことを実装するのであれば、Y.H.さんのコードのように書きます。中身を理解できても、ぱっと見でわからなければ、それは私にとって価値が無いコードだからです。
投稿2019/09/27 10:49
編集2019/10/10 09:34総合スコア21737
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/28 06:34 編集
2019/09/28 06:44
2019/09/28 07:36
2019/09/28 08:49 編集
2019/09/28 08:56
2019/09/28 09:08
2019/09/28 09:17
2019/09/28 09:31
2019/09/28 09:35
2019/09/28 10:11
2019/10/09 08:29
2019/10/09 12:01 編集
2019/10/09 12:43
2019/10/09 16:31
2019/10/09 22:15
2019/10/09 23:39
2019/10/10 00:37
2019/10/10 00:44 編集
2019/10/14 14:21
2019/10/14 18:10
2019/10/15 00:54
2019/10/15 01:04
2019/10/15 01:20
2019/10/15 01:27
2019/10/15 02:17
2019/10/15 02:38
2019/10/15 02:46 編集
2019/10/15 02:54
2019/10/15 03:07 編集
0
++Move > 40
これが評価される時点でインクリメントされます
結果がどーこーは関係ありません
投稿2019/09/26 09:13
編集2019/09/26 09:14総合スコア88040
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/26 09:26
2019/09/26 09:46
2019/09/26 10:02
2019/09/26 11:14
2019/10/10 01:01
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/09/26 10:35
2019/09/26 10:42
2019/09/26 10:46
2019/09/26 11:30
2019/09/27 00:22 編集
2019/09/27 00:15
2019/09/27 00:21
2019/09/27 00:54
2019/09/27 01:34 編集
2019/09/27 02:31
2019/09/27 02:53
2019/09/27 02:56
2019/09/27 03:20
2019/09/27 03:29
2019/09/27 06:54 編集
2019/09/27 08:51
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。