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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

5回答

3343閲覧

&&の条件文について。

PaperZ

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

2クリップ

投稿2019/09/26 09:09

前提・実現したいこと

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ページで確認できます。

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2019/09/26 09:21

また新しいアカウント。
cateye

2019/09/26 10:21

C言語の文法、特に演算子の優先順位と式の評価順を勉強しましょうd^^
PaperZ

2019/09/26 10:28

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

2019/09/26 15:11

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

2019/10/10 10:25

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

回答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
Y.H.

総合スコア7914

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PaperZ

2019/09/26 09:24

Moveが0より大きいですが、例えばまだMoveが7とかの場合、++Move > 40の条件を満たしていないと思うのです。なのになぜ正しく動くのかわかりません。
Y.H.

2019/09/26 09:56

回答に追記しました。 一度PaperZさんの考えてられる動作を &&を使わずにif文を分けて書いてみると 違いがわかると思います。
rubato6809

2019/10/09 22:21 編集

if文を分けて全く同じ動作のコードにしてみた・・・そう、これを分かってもらうことが肝心だと思う。そして書き直したコードをフローチャートに描いてみたら良いと思う。ここに言及しないということは、質問者は誤解したままじゃないだろうか。
Y.H.

2019/10/10 00:44

>rubato6809さん でしょうね。短絡評価により &&の左項が偽の場合、右項は評価されないという部分に関しては質問者さんのコメント見ると理解されてないようですしね。。。。
PaperZ

2019/10/10 07:24

if (Move > 0 && ++Move > 40)を分解したプログラムが if (Move > 0 && ++Move > 40)がどのように処理されるかを表しているとわかりました。
PaperZ

2019/10/10 07:28 編集

Y.Hさんは、どのように勉強されたことで if (Move > 0 && ++Move > 40)が if (Move > 0) { Move=Move+1; if (Move > 40) { Move = 0; の順番で働くとわかったのでしょうか。
Y.H.

2019/10/10 07: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;} }
PaperZ

2019/10/10 07:51

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

0

ですが&&よりMove自体は40より小さいため

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

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

投稿2019/09/26 10:18

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PaperZ

2019/09/26 10:28

「++Move > 40を満たしていないため+1されない」が間違いだから。 では、正しくはなんでしょうか。
episteme

2019/09/26 11:38

「++Move > 40の真偽にかかわらず+1される」
fana

2019/09/27 01:40

(わざわざ自分でどう動くか把握できない形でコードを書いているのだろうか…?)
PaperZ

2019/09/27 06:44

たまに忘れてしまうんです。 その時は理解しながら書いても改めてみると忘れてしまったりします。 厄介ですいません。
PaperZ

2019/09/27 06:50

優先順位などがきっちり理解できていなかったようです。
episteme

2019/09/27 07:01

あなたの誤解:「++Move > 40を満たしていないため+1されない」 には優先順位は何の関係もない。
PaperZ

2019/09/27 07:11

優先順位とか関係なく、左から評価され、左が偽だったら右は評価しないということでしょうか。
episteme

2019/09/27 07:15

それは&&演算子の短絡評価。やっぱり無関係。
PaperZ

2019/09/27 07:23

うまく理解できなくてすいません。 「++Move > 40の真偽にかかわらず+1される」とのことですが、なぜ++Move > 40の真偽にかかわらず+1されるのでしょうか。優先順位とかは無関係とわかりましたが、だとしたらどういう理由で++Move > 40の真偽にかかわらず+1されるのか知りたいです。
fana

2019/09/27 07:26

「Moveの値をインクリメントする.インクリメントした結果の値が40より大きいかどうか判定する」 というプログラムをあなたが(まぁ,あなたではないらしいが)書いたから. 「Moveの値をインクリメントする」んだからインクリメントするんだよ. 40との比較がどうの以前にまずインクリメントするんだよ.
fana

2019/09/27 07:30

「40との比較を行う前に,まずはMoveの値をインクリメントする.その後で(インクリメントした結果の)Moveの値と40とを比較する」と書けばいいか.
episteme

2019/09/27 07:35

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

2019/09/27 07:48

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

2019/09/27 08:00

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

0

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

評価(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/09/27 10:49

編集2019/10/10 09:34
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PaperZ

2019/09/28 06:34 編集

ありがとうございます。 読ませて頂きました。例えばif (move <= 500 && --move > 0)の場合、 moveが0の時、500以下であるため左の条件には真となり右に進みますが、 --move > 0の条件には‐1されると0より小さい‐1になるので偽となり、結果として真&&偽より偽になるので出力は0のままかと思ったのですが、‐1となっていました。 if (move <= 500 && --move > 0)に関してはどのような原理で値が変動して、今回のようになったのでしょうか。
PaperZ

2019/09/28 06:44

どうかif (move <= 500 && --move > 0)の場合の図も書いて詳しく説明して頂けないでしょうか。 よろしくお願いいたします。
raccy

2019/09/28 07:36

あなたは同じように図を書いてみましたか?もっと言えば、書こうとしましたか?自分で書かない限り、身に付くことは一生ありませんし、理解することもありません。あなたが自分で図を書かない限り、他の人は一体どこが間違っているのか指摘することもできません。自分の今の考えを図にしてみて、私の図と見比べて、何が違うのか考えてください。考えても全くわからないというのであれば、その時にまた質問してください。
PaperZ

2019/09/28 08:49 編集

すいません、最初の図において最後moveの値は0になるのでしょうか。
raccy

2019/09/28 08:56

図の吹き出し部分を読みましたか?読んでいないなら、読んでください。読んでいるなら、自明かと思います。読んだけども意味がわからないなら、吹き出しの文章のどこが不明なのかを聞いてください。読んでいて、意味もわかっていて、それでもMoveの値が何になるのかわからないというのであれば、なぜあなたにわからないのか私にはわからないため、これ以上説明することはできません。
PaperZ

2019/09/28 09:08

moveがインクリメントされて2になります。ですが左の項は++move>40なので偽となります。 そして、なので真&&偽となるため結果は偽になると思います。偽となったためmoveの値は1のままかと思ったのですが、2となっているように読み取れました。なぜ真と偽により結果は偽になっているのに2になったのでしょうか。優先順位などが関係しているのでしょうか。
raccy

2019/09/28 09:17

結局、あなたは図からMoveは何になったと読み取ったのですか?0ですか、1ですか、2ですか、それとも別の何かですか?
PaperZ

2019/09/28 09:31

2です。
raccy

2019/09/28 09:35

なら、あなたの疑問はもう無いですよね。Cは図の通りに各式が評価されるという話だけですから。
PaperZ

2019/09/28 10:11

結果は偽で{}の中身が実行されないだけで、++が評価されたのでmoveは2となったのですね。
PaperZ

2019/10/09 08:29

move>0&&++move>40、これって変数moveは40より大きくなりますよね?
raccy

2019/10/09 12:01 編集

質問のコードでの話でしょうか?質問のコードでは直前に`int Move = 1;`と書いていますので、その式が評価される前にMoveが1以外の値であることはあり得ません。よって答えはは自明かと思います。 質問のコードの話ではなく、別のコードの中にある話であれば、そのコード全てを見ないことにはわかりません。
episteme

2019/10/09 12:43

> move>0&&++move>40、これって変数moveは40より大きくなりますよね? if ( move>0&&++move>40 ) { ... } が何度も繰り返されたら 40より大きくなるか? # ただしmoveをこの条件式以外で変更しない と質問しているのなら: moveの初期値が 0以下であるなら 何度繰り返しても値に変化はない。 moveの初期値が 0より大きいなら、繰り返しのたびに+1される。
PaperZ

2019/10/09 16:31

どうもありがとうございました。
rubato6809

2019/10/09 22:15

低評価。 右辺値、左辺値、遅延評価・・・こんな言葉を使っても、この質問者に届かない。さらに混乱させてるようだ。
PaperZ

2019/10/09 23:39

どのように理解すればいいでしょうか。 基礎本を読みましたが、if ( move>0&&++move>40 ) のような例がないため理解に困っています。
episteme

2019/10/10 00:37

Y.H.さんが等価なコードを示してくれている。
episteme

2019/10/10 00:44 編集

例がないと理解できない? 九九の表に載ってないから2桁の掛け算ができません てか? 基本的なルールの組合せだ。
PaperZ

2019/10/14 14:21

epistemeさん、あなたの考えは間違っています。 あなたはif(++Move > 0 && Move > 40)とif(Move > 0 && ++Move > 40)を同じもののように言っていましたが、この二つは違うものです。 if(++Move > 0 && Move > 40)はMoveの値に関係なく+1されていき Move > 40になったら{}の処理を行い(Moveの値に関係ないため、++Move>0と書く意味はないのでif(++Move && Move > 40)と書いても同じ)、if(Move > 0 && ++Move > 40)はMoveが0より大きい時に+1されていきMoveが40より大きくなったら{}の処理を行うことを表します。
episteme

2019/10/14 18:10

> あなたはif(++Move > 0 && Move > 40)とif(Move > 0 && ++Move > 40)を同じもののように言っていましたが、 どこで?
PaperZ

2019/10/15 00:54

個人で連絡を取らせて頂いた際にそういって言ったような気がします。
episteme

2019/10/15 01:04

個人で連絡? あなた誰? なぜココで?
PaperZ

2019/10/15 01:20

忘れてしまったならいいです。
episteme

2019/10/15 01:27

PaperZを名乗るかたと個人的な繋がりはないので人違いでしょうし、そうでなくてもココは場違いかと。
PaperZ

2019/10/15 02:17

なぜ場違いなのでしょうか。
episteme

2019/10/15 02:38

個人的なやり取りを 一方が他方の承諾なく 公にしていいわけがない。
Zuishin

2019/10/15 02:46 編集

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

2019/10/15 02:54

わかりました。
episteme

2019/10/15 03:07 編集

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

0

++Move > 40

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

投稿2019/09/26 09:13

編集2019/09/26 09:14
y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PaperZ

2019/09/26 09:26

だとしたら&&の意味がない様に思えるのですが、 0より大きくてかつ40より大きい際にインクリメントされていると思っていました。
Y.H.

2019/09/26 09:46

0より大きくて かつ Moveに1足してその結果が40より大きい際に、Moveに0を入れAに10をいれる。 というコードです
y_waiwai

2019/09/26 10:02

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

2019/09/26 11:14

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

2019/10/10 01:01

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

0

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

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

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

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

投稿2019/09/26 09:38

moredeep

総合スコア1507

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

PaperZ

2019/09/26 10:35

if (time >= 0 && ++time < 20)の場合は 1しか上がらなかったのですが、20より小さい19などの値まで+1されて上がると考えていたのですが、 ++time < 20が20より小さい値すべてに反映するため1しか上がらなかったのでしょうか。
Y.H.

2019/09/26 10:42

if()の条件が成立し Move=0 が実行されたからです。
Y.H.

2019/09/26 10:46

ステップ実行できる環境は無いのですか? 無いのならまずステップ実行できる環境を用意されることをおすすめします。 理解度が飛躍的に上がりますよ。
PaperZ

2019/09/26 11:30

まず全体Move > 0 && ++Move > 40を読み込んでから、 コンパイラでは++が優先順位が高いのでMoveが+1されていき Move > 0とMove > 40の>により、40より大きくなり &&によりどちらの条件も満たすように作ったので、思った通りに動くとわかりました。 理解出来ました。
Kapustin

2019/09/27 00:22 編集

↑(ご注意)ちょっと違う理解になっているかもしれません。 例題の初期値 int Move=1; の場合は最終的に Moveの値が 2 になりますが、 初期値を int Move=0; や int Move=-3; にした場合に、最終的に Moveの値がいくつになっているか想定してみたあと、実際に実行してみてください。 ``` #include "stdio.h" int main() { int A; int Move = 1; // int Move = -3; if (Move > 0 && ++Move > 40) { Move = 0; A=10; } printf("%d\n", Move); return 0; } ``` > moredeep様 回答欄お借りしてすみません!
moredeep

2019/09/27 00:15

優先順位はコンパイラが判断するものです。コンパイラは機械語を生成し、コンピュータは機械語の命令を実行します。 そこを混同してしまうと、私の回答はわけがわからないか、間違った解釈になってしまいます。 コンパイラは優先順位に従って、1つの行を複数の処理に分解します。そのため、コンパイルした後のプログラムはY.Hさんが追記で提示されたコードとほぼ同一になるはずです。 とりあえず言えるのは(新人によく言っているのは)、よくわからないならif文にはbool型の変数一つだけ入れるようにしてください。
Zuishin

2019/09/27 00:21

優先順位と評価順について、この質問のケースでは合っていますが、一般論として少し違うので低評価しました。
moredeep

2019/09/27 00:54

すみません、説明が雑でしたね。よければ補足してください。
Zuishin

2019/09/27 01:34 編集

https://ja.cppreference.com/w/c/language/eval_order > あらゆる C の演算子の被演算子の評価順序 (関数呼び出し式の関数引数の評価順序を含む) およびあらゆる式の部分式の評価順序は (下で述べられている点を除いて) 未規定です。 あと、これは副作用の話ですが、++Move を Move++ に変えると、この回答の考え方では説明しきれなくなると思います。 また FALSE && ++Move という式の場合、&& よりも ++ の方が優先順位は高くなりますが、実際には ++Move は評価されないだろうと思います。
moredeep

2019/09/27 02:31

Zuishinさんの書かれた内容は正しいことですが、すみませんが、少しだけ追記させてください。 後置きと前置きの違いは、(特定のコンパイラでは)一時変数を作っていただけだったと思いますので、それを例にとれば順序に限っては特に説明しきれなくもないかなと。 最後のやつは、論理演算子の短絡評価の話でまた別の話ですし、優先順位の話をしているのは&&の右側だけです。(説明が足りないという指摘でしょうか?) とりあえず、断定口調だったのがいけなかったってことを理解しました。気を付けます。
Zuishin

2019/09/27 02:53

実装がどうなっているかは言語とは無関係です。短絡評価は、優先順位と評価順序が必ずしも一致しないことの一例で、同じ問題です。 私が低評価した理由は、断定口調だからではありません。優先順位と評価順序を混同した回答であり、初心者を混乱させる回答でもあるからです。 https://ja.cppreference.com/w/c/language/operator_precedence > 優先順位と結合性は評価順序とは無関係です。 ですが、この回答では、評価順序で説明すべきところを優先順位で説明しています。 FALSE && Move++ < 1 これはかっこでくくると次のようになります。 (FALSE) && ((Move++) < 1) しかし ++ は < よりも優先順位が高いにも関わらず、副作用の評価は < よりも遅くなります。 Move の初期値が 0 の時、Move++ < 1 は真になりますが、かっこでくくって説明すると Move が 1 に見えます。初心者への説明として良いとは思いません。
Zuishin

2019/09/27 02:56

後置インクリメントは初心者が迷うポイントの一つですが、この回答はまさにその迷いの道へとみちびくものです。
moredeep

2019/09/27 03:20

評価順序って、一つの式の中の部分式の順序だったと思うのですが、違いましたか?(あらゆる式の部分式の評価順序) つまり、 (FALSE) && (xxx)←これが一つの式と部分式が2つ、ただし短絡評価がある 部分式(xxx)を評価するときに (Move++) < (1)←これが一つの式と部分式が2つ、これにフォーカスして回答している →1の評価とMove++の評価の順序(評価順)は不定です。 たとえば、(IncrementAndGetMove()) < (GetMove())のようにしたらおかしくなるというのは間違いないですが、部分式より先に全体の式が評価されることはないと考えています。それは、関数の引数を評価する前に関数に値を渡すことと同義かと。 副作用の評価は < よりも遅くなります。と断定されていますが、 if(FALSE) { int temp = Move; Move += 1; if(temp < 1) {...}}でもいいわけですよね? こういう考えもあるよ程度にぼかさなかったのが一番の行き違いの元凶かなと思ったわけです。
Zuishin

2019/09/27 03:29

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

2019/09/27 06:54 編集

> 関数の引数を評価する前に関数に値を渡すことと同義かと。 いえ、違います。関数呼び出しは副作用完了点ですが、&&、||、? :を除いた演算子の評価はそうではありません。 https://www.jpcert.or.jp/sc-rules/c-exp30-c.html
fana

2019/09/27 08:51

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問