
◎1--------------------------------------
#include<stdio.h>
int main(void)
{
int i=0;
while(i<=20){
printf("%d\t%d\t%d\t%d\t%d\n",++i,++i,++i,++i,++i);
}
return 0;
}
------------------------------------------
◎2--------------------------------------
#include<stdio.h>
int main(void)
{
int i=0;
while(i<=20){
printf("%d\t%d\t%d\t%d\t%d\n",i++,i++,i++,i++,i++);
}
return 0;
}
------------------------------------------
以上2つのプログラムについて疑問があるのですが、まず◎1についてですが、実行結果は、
5 4 3 2 1
10 9 8 7 6
15 14 13 12 11
20 19 18 17 16
25 24 23 22 21
以上のようになるのですが、自分の考えでは、「printf("%d\t%d\t%d\t%d\t%d\n",i++,i++,i++,i++,i++);」部分の、一番最初の「++i」から処理が始まり、
1 2 3 4 5
・
・
・
のようになる事を期待したのですが、一番最後の「++i」から処理が始まってしまいました。
次に、◎2についてですが実行結果は、
0 0 0 0 0
5 5 5 5 5
10 10 10 10 10
15 15 15 15 15
20 20 20 20 20
以上のようになりました。「printf("%d\t%d\t%d\t%d\t%d\n",i++,i++,i++,i++,i++);」部分で、iをいったん表示してから、iに1を加算するということで、次のiは1になっており、
4 3 2 1 0
・
・
・
のようにまた一番最後の「i++」から処理され以上のようになると思ったのですが、そうはなりませんでした。
以上、◎1と◎2について何故こうなるのかご回答いただければ嬉しいです。
No.3ベストアンサー
- 回答日時:
既に回答があるように, Java とは異なり C/C++ では引数の評価順序について何も規定されていません. もっというと, 少数の演算子を除いて評価順序の規定は存在しません.つまり, 5個あるインクリメントをどの順に評価するかは全く分からないのです.
もっというと, この例では #1 でいわれるように 2つの副作用完了点の間で i の変更が複数回行われているので, その結果は未定義となります. つまり「どのような結果になるか規格では一切関知しない」ということです. なお, この場合「直前の副作用完了点」は前の分の終わりに, 「直後の副作用完了点」は関数 printf の呼び出しの直前にあります.
以下余談ですが, 「わざわざ区別するのも面倒なので, 常に後ろの引数からスタックに積む」処理系もわりと普通のような気がしますがいかがなもんでしょうか>#2.
ああ, もちろん「スタックに積む」とは規格のどこにも書かれていないので注意してください.
ご回答ありがとうございます。
>引数の評価順序について何も規定されていません. もっというと, 少
>数の演算子を除いて評価順序の規定は存在しません.つまり, 5個ある
>インクリメントをどの順に評価するかは全く分からないのです.
>もっというと, この例では #1 でいわれるように 2つの副作用完了点
>の間で i の変更が複数回行われているので, その結果は未定義となり>ます. つまり「どのような結果になるか規格では一切関知しない」と
>いうことです.
以上、細かくご説明ありがとうございます。
以上のご回答をふまえ、もっと勉強してみます!

No.6
- 回答日時:
すでに回答があるように、この動作は、「未定義」とされています。
つまりは、printf() の実行後に i が 5 増えているとすら、断言できないというのが、規格上は正解です。
多くのコンパイラではそうなるでしょうが。
参考URL:http://www.kouno.jp/home/c_faq/c3.html#2
ご回答ありがとうございます。
みなさまからのご回答にもありましたが、「二つの副作用完了点の間に、オブジェクトの値を2回以上変更している場合」は動作が未定義であるとわかりました!
No.5
- 回答日時:
当該のprintfの初回実行直後の
iの値は5である、としか言えません。

No.4
- 回答日時:
#2 です。
間違いを書いてしまったので訂正です。(まあ、「例」なので、間違いじゃないと言えなくもないかも)
ご指摘を受けて、調べてみたら、そもそも、「引数を積むのは無条件に右から左」がむしろ、主流(少なくともよくある例)のようです。
そういうわけで、
---------------------------
「多くのコンパイラが、引数を、「左から
(先頭から)順に積み上げ、反対側(後ろ
から)順に処理する」という挙動をします。
---------------------------
というのは間違いでした。
※よく考えたら、「多くのコンパイラが」と書いている時点で間違いですがな。
>「引数を積むのは無条件に右から左」がむしろ、主流(少なくともよくある
>例)のようです。
以上のご回答理解しておきます!
ありがとうございました。

No.2
- 回答日時:
正解は既に回答があるとおり、「何が
起こるかわからない」「何が起こって
も文句は言えない」です。
ただ、具体的な動作の例は、以下のよ
うなものがあります。
※これは、あくまでも、「あるコンパ
イラはこういう動きをする」というだ
けで、そうでなければ、ならないとか、
そのような動きを期待してもいいとか
言う意味ではありません。
C言語では、多くの場合、関数への引
数渡しは「スタック」が使われます。
結論から言えば、多くのコンパイラが、
引数を、「左から(先頭から)順に積み
上げ、反対側(後ろから)順に処理す
る」という挙動をします。
引数の評価は、関数の呼び出し前(引
数をスタックに積み上げるとき)に行
われるので、多くの場合、引数は左 →
右の順に評価されます。
ただ、printf() のような「可変引数」
の関数は事情が異なってきます。
この場合、最初の引数を理解しないと、
引数の数すら把握できません。
従って、「可変引数」の関数は、逆に
「右から(先頭から)順に積み上げ、
反対側(前から)順に処理する」
ということになります。このため、引
数は通常とは逆に、後ろから(右 →
左)の順序で評価されることになります。
あと、++ を前置したときと後置したと
きの挙動ですが、入門書には、時々
前置:インクリメントしてから、評価
後置:評価してからインクリメント
と書かれていますが、これは、厳密に
は間違いです。
正解は、
前置:評価結果はインクリメント後のもの
副作用として、インクリメント実施
後置:評価結果はインクリメントする前の
もの、副作用としてインクリメント
実施
になります。
つまり、評価とインクリメントの時間的な
関係までは規定されていないのです。
ですから、
a = (i++) + (j++);
の場合、
・i を評価して、インクリメント
・j を評価して、インクリメント
でもいいですし、
・i を評価
・j を評価
・i をインクリメント
・j をインクリメント
の順序で動作してもOKです。
今回の例では、
・i をそれぞれ評価して、
・あとで、i をそれぞれインクリメント
という動作にしているのでしょう。
(ただ、次の式が評価される「前」には終
わっている必要はあります。これが、回答
にある「副作用完了点」というものです)
以上は、あくまでも、「そういう例もある」
「そういう例なら、今回のような結果になる」
というだけで、「これが正しい動作」では
ありません。
ご回答ありがとうございます。
インクリメント処理が副作用、評価結果が副作用完了点とわかりました。
評価とインクリメントの時間的な関係までは規定されていないということもわかりました!
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングペーパーテスト 次の問題の実行結果を答えろ #include int x[ ] = { 1 2022/06/16 21:49
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# プログラミングの授業のペーパーテスト 実行結果を答えろ #include int x[ ] = {1 3 2022/06/16 20:08
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# プログラミングのペーパーテスト 実行結果を表示せよ #include <stdio.h> int h 1 2022/07/09 15:27
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# プログラミングのペーパーテスト 実行結果の表示を答えてください #include <stdio.h> 2 2022/07/09 16:14
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
このプログラムの実行結果につ...
-
テキストカーソル位置の取得
-
改行について 1行に何個かづ...
-
C言語で四則演算を使って10を作...
-
Cのdoubleの浮動小数点表示につ...
-
基本的に問題
-
C言語の問題について教えていた...
-
C言語 プログラミング
-
カレンダーのプログラムについて
-
for文内でscanf関数により配列...
-
球の体積と表面積を表示するプ...
-
10個出力で改行したいのですが...
-
getcharの連続について
-
C言語で四則演算を使って結果が...
-
C言語のプログラミングがうまく...
-
インクリメント演算子について
-
共用体の個々のメンバのアドレ...
-
printf で二進表示を行いたい。
-
DOSコマンドで、YES,NO条件を加...
-
コマンドラインに出力した文字...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
コンパイルエラーについて
-
printf で二進表示を行いたい。
-
コマンドラインに出力した文字...
-
(C言語)めちゃくちゃな値にな...
-
c言語でAからZまでを表示する...
-
printfの出力内の文字をdefine...
-
defineで定数が置き換えられな...
-
c言語で2000年以降カレンダーを...
-
cshの文字列操作(0埋め)
-
10個出力で改行したいのですが...
-
4の倍数を論理演算で表す。。
-
ホームページをC言語で作りたい...
-
コマンドプロンプトがすぐ消える
-
教えてください!!
-
Cプログラムについて
-
サイコロをふって、出た目のパ...
-
strcmp
-
じゃんけんゲームの応用
-
C言語でマウス入力(クリックや...
-
printfの有無で値が変化する
おすすめ情報