【goto文使いのプログラミングの考え方は?】


構造化をサポートする言語(C/C++, Javaなど)を知る前に、行番号付きBASICやアセンブリ言語のようなgoto文(ジャンプ命令)ありきの言語を習得した人はどういう発想でプログラミングしているのでしょうか?

私は構造化言語(C言語)を先に習得したので、アルゴリズムをif文やwhile文の組み合わせで考えてから、アセンブリ言語の場合、それをジャンプ命令によって置き換えていきます。私にとって、これ以外の考え方ができないわけですが、非構造化言語を先に習得した人はgoto文ありきでサクサクとプログラミングしてるんでしょうか?その辺の感覚的なところであるとか、そうした上でスパゲティコードにならないように気をつけている点などありましたら、教えてください。

回答の条件
  • 1人3回まで
  • 登録:2007/12/29 01:54:40
  • 終了:2007/12/29 17:25:45

回答(4件)

id:Kumappus No.1

くまっぷす回答回数3784ベストアンサー獲得回数1852007/12/29 04:02:18

ポイント30pt

行番号(ラベル)ジャンプしかできない言語といえばFORTRANのほうが先だろう、とは思いますがそれはおいといて。

初めて覚えたのはTK80BSのBASICやTiny BASICや電大版BASICでしたかね>私の場合。

BASICでも別にFOR文などはあったのでループの感覚はありましたし、IF文もあったわけだし、構造化言語になったからといって全然苦労しませんでした。

例えば

10 IF A = 10 THEN 40
20  PRINT "A is not 10"   ←ELSEの処理
30  GOTO 50 ←ELSEが終わって抜ける指示
40  PRINT "A is 10"
50 REM 次の処理

のようにIF THEN ELSEは「開いて」書いていただけです。30行目の処理などが「余分な手間」ですけどね。

構造化言語のコンパイル結果(アセンブリコード)もほぼこれに準じた並びになっているわけです。

それからBASICの方言で、GOTO文の後に式が書けるものがあり

10 GOTO 20+X*20
20 PRINT "X=1"
30 GOTO 100
40 PRINT "X=2"
50 GOTO 100
60 PRINT "X=3"
70 GOTO 100
...
100 REM 次の処理

これなんかCのswitch文に近い感覚だと思います。実際レジスタの値をプログラミングカウンタに加算する、という命令にコンパイルされていることもありましたしね>Cのcase文。

もちろん、中には処理を飛ばしまくって(例えばデバッグをしていく過程で行番号が詰まってしまって処理を別のブロックに書いて戻さないといけないということがあった。後にRENUM命令ができるようになって解消しましたが)、ぐちゃぐちゃになったプログラムもありますけど、これだってCで無駄にネストが多い関数呼び出しなんかすると同じことだし。トリッキーなことをやると後で苦労するのはすぐに学習したからGOTOを駆使して(Cのswitch文でbreak使わないのと同じようなもの)ステップを節約する、なんてのは早々にやめました。

で、

どういう発想でプログラミングしているのでしょうか?

ですけど、これは上記のように「手でブロックを脱出したりする処理を余分な手間として書いていた」ところが不要になって楽になったな、ということにしか感じませんでした、私の場合。

ただ、「全ての行の前に LABEL10: LABEL20:…のようにラベルがついていてgotoで飛ばしているCソース」というのを見て卒倒しそうになったことはあるのでそうじゃないひともいるのでしょう。

高級言語ほどそういう細かいところを気にしないでバリバリ書いていけるので楽だなあと思います(最近はなるたけC#などのガーベージコレクションつき、ポインタなしな言語を使うようにしています。そのうち「malloc(),free()などでメモリを管理するプログラミング言語を先に習得した人は…」なんて質問が出るのだろうか)。

今のところ「関数型言語」あたりになると今まで培ってきた発想法ではちょっと壁がありそうですが(monadとかー)、そこに行きつくまでならどの言語でもだいたいプログラムできますしね。

参考:(一応「笑い話」なので、そこんところ注意)

http://www.genpaku.org/realprogrammerj.html

id:witt

BASICにもIF文、FOR文があったのですね。勉強不足でした。

アセンブリ言語でのプログラミングの考え方について、これといった情報がなくて不安が覚えていたのですが、Kumappusさんの発想法は、私のものと近くて安心しました。

2007/12/29 10:56:11
id:garyo No.2

garyo回答回数1782ベストアンサー獲得回数962007/12/29 08:14:04

ポイント28pt

ようは慣れでしょうね。

私は20年以上プログラミングをやっています。

1PASSアセンブラのブランチ命令では一度アドレスの差をとりそれが負であれば2の補数として手計算します。

2PASSアセンブラでジャンプやブランチのとび先にラベルが使えるようになり

構造化アセンブラでIF文やWHILE文マクロが使えるようになります

行番号付きBASICも最初は各PC固有のBASICで飛び先は行番号しか使えず

その後飛び先にラベルが使えるようになります。


機械語レベルの制御命令は、CISC系では無条件ジャンプ、演算フラグによる条件ブランチしかないので、この2種類があれば原理上どんな処理でも可能(それ以外の制御文はこの2つに書き直されて実行されているわけ)です。

(さすがにRISCのアセンブラは手作業では書きたくないですけどね。機械に読みやすく人間に読みにくいコードですから)

制御文などは特に意識しなくても書けますが、それより数の少ないレジスタをどう効率よく使いまわすかが問題でしたね。

昔は一度プリントしたソースに矢印でどこからどこへ飛んでいるか線を引いたりしていましたね。

最近ではアセンブラも構造化アセンブラになってあまりJumpとか意識していないのではないでしょうか。

昔はC言語を構造化アセンブラ代わりに使ったりしていましたね。自動生成のコードは効率が悪いので手直ししたりしていました。

if(a!=0){} と if(a){} では生成される命令が違っていたりとか構造体の配列を使うと内部のアドレス計算に時間のかかるMUL命令を使うので遅いとか。

最近では全く不要の知識ですが。

id:witt

>制御文などは特に意識しなくても書けますが、

こういう人がいるので、かなり意識する私は、その人の頭の中身が知りたかったわけです。

>ようは慣れでしょうね。

やはり・・・

この一言で済まされると、アセンブリ言語のプログラミングの考え方について、説明のしようがなくなっちゃんですが、現実的にそうなんでしょうね。構造化プログラミングやオブジェクト指向プログラミングの概念のような模範があればと思ったんですが。

2007/12/29 11:09:41
id:tezcello No.3

tezcello回答回数460ベストアンサー獲得回数692007/12/29 10:48:25

ポイント30pt

8080(Z80)でハンドアセンブルをやっていた頃は、バイト数の節約などで同じ様な処理をしているサブルーチンの途中へ飛ぶようなジャンプを使ったりしていましたね。

そんな特殊な場合を除けば、ループを形成する為(for, while 的な使い方)、ループからの脱出(break, continue, next 的な使い方)サブルーチン的な利用 として使われるのでは?


アルゴリズムを考える時は「○○が△△するまで繰り返し□□する」を考えるのではないでしょうか?

それが決まれば、ループの先頭にラベルをつけ、ループエンドで条件判断してラベルへジャンプ

flag = 0;
ANLIZELOOP:
  ...
  ...
  ...
if (flag != finish) goto ANLIZELOOP

と決り文句のようにコーディングするだけなので、考え方としては for, while を当てはめているのと全然変わりません。(上の例では、do{...}while() と同じでしょ?)

によって書き方が異なるでしょうから、慣れないと他人の書いたコードはスパゲティボールのように見えるかも知れませんが。


1本のスパゲティ(GOTOで呼び出している所、戻り先が固定)なら、ピンと延ばせば1直線なので全然問題無いですが、複数のスパゲティが絡み合っていて、割れたりくっついたいしているの(=スパゲティボール)は書いた本人もぱっと見はわからないかも知れませんねぇ。

そんなコードをわざと書く事は出来ると思いますが、普通に書いていけばそんなに無茶なコードにはならにように思います。(ある意味特殊な才能が必要でしょう)

GOTOの文字があるだけで毛嫌いする人が多くいましたが、個人的にはそれ程嫌いじゃないです。

if(){...} と括った範囲がやけに長いとか、そのネストが深いとか、名前から動作を推測できないような関数が並んでいる方が理解し難いと思います。

id:witt

tezcelloさんの発想法も私のものに近いので安心しました。

上記では、do{...}while()のコードを書いてもらいましたが、

私の場合、下記に対応するコードをテンプレートとして用意しておき、

コーディング時にそれに当てはめていく感じです。

・if(){...}

・if(){...}else{...}

・if(){...}else if(){...}

・if(){...}else if(){...}else{...}

・while(){...}

・for(){...}

・サブルーチン呼び出し

もう少し慣れれば、テンプレートなしでもコーディングできるようになるんでしょうが、

私の考え方はあながち間違ってないと感じました。ありがとうございます。

2007/12/29 11:45:09
id:KUROX No.4

KUROX回答回数3542ベストアンサー獲得回数1402007/12/29 12:56:43

ポイント40pt

>非構造化言語を先に習得した人はgoto文ありきでサクサクとプログラミングしてるんでしょうか?

ニュアンスは違いますけど、YESでしょうね。

>アルゴリズムをif文やwhile文の組み合わせで考えてから、

>アセンブリ言語の場合、それをジャンプ命令によって置き換えていきます。

アセンブリ言語でも、構造化を意識してというかそういう思想でプログラム

しないとスパゲティになるので、(無意識に)構造化らしいことはしてますね。

IFやWhileとか意識しないで、ダイレクトにアッセンブラに落としているので

置き換えてるという感覚はないです。文面からみるとC言語で考えてからアッセンブラに

落とすように読み取れるので・・・。

慣れだと思います。

Goto文はこの際あまり関係ないと思います。

非構造化言語を先に習得した人は、どういうgoto文を使ったらNGなのかを良く分かっているので

さくさくとコーディングできるという話はあろうかと思います。

C言語でも、多重ループを抜けるときなどは、非構造化言語を先に習得した人ほど、gotoで

さっくり抜けるコードを書く傾向に高いと思います。構造化言語のひとは、gotoの有効な使い方

を知らない人が多いのと、gotoを使うと構造化してないと勘違いする人がいるので、困ったもんだ

と思います。

id:witt

なるほど。直接アセンブリ言語レベルに落とし込めるのですね。納得できました。

2007/12/29 17:24:08
  • id:wasisan
    質問と関係ないのでコメントとします.

    まず,if/while文についてですが,BasicにはIF文,WHILE文(For文も)は存在していました.
    アセンブリ言語はよく知りませんが,当然IF文はある(WHILEはGOTOするみたいですが).


    たぶん不足していたのは''関数定義・スコープ制御''の感覚だけではないでしょうか.

    だから,スパゲティコードにならないために重要なのは,

    ・ルーチン間の移動を明確に
    MASMではCall文がある.BasicではGOTOは使わずGOSUBを使う.

    ・変数の有効範囲を分かりやすく
    例えば,アセンブリ言語では関数の引数はスタックにPOP/PUSHしてやると思います.
    Basicでは引数専用の変数を使うとか.

    ということになりましょうか.

    あと,構造化されている言語だからといってgoto的なジャンプが不要になるということはありません.
    Java/C++にある例外処理(try/catch)はgotoみたいなものです.
    これは上手く使わないとスパゲティコードになってしまうと思います.


    さらに余談ですが,whileループではスパゲティになりやすい
    アルゴリズムも多いということもありますので.

    なんでも再帰: http://practical-scheme.net/docs/tailcall-j.html
    とか読んでみてください.
  • id:witt
    なるほど。

    では、構造化言語習得者は、非構造化言語おいても構造化言語の流儀に従ってプログラミングすれば、
    きれいなコードを書けるわけですね。

    >あと,構造化されている言語だからといってgoto的なジャンプが不要になるということはありません.
    >Java/C++にある例外処理(try/catch)はgotoみたいなものです.
    >これは上手く使わないとスパゲティコードになってしまうと思います.

    同意です。私は、Cで入れ子のループを抜けるときにも、goto文を使います。
    ただし、goto文で絶対やっちゃいけないなぁ、と思うことは、下から上へ制御を流すことです。
    これをやられると簡単にスパゲティコードになってしまうんで。

    コメントありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません