電子書籍の厳選無料作品が豊富!

私は組み込みでソフト開発を行っているものです。
(アセンブラでの経験は長いが、Cは短い)
基本的な質問になってしまいますがご了承ください。
C言語で"goto文は使うな、スパゲティプログラムになりやすい。
使うなら多重ループからの脱出のみ" ということを良く聞きます。
本当ににそうでしょうか?・・・

例えば、下記サイトの図6をC言語で書いてみました。
もちろんgotoを使いました。
gotoを使わないで、誰でもわかりやすく書くことなどできるのでしょうか?
よろしくお願いします。


http://techon.nikkeibp.co.jp/article/NEWS/200711 …



/* 開始 */

KAISHI:
p74 = High;

if(p70 == High){
register = 1;
}
if(p71 == High){
register = register + 1;
if(register != 1){
goto KAISHI;
}
if(p72 == High){

A 回答 (16件中11~16件)

私はジジイですが、C/C++でgotoを使った経験もないですし、使おうと思ったこともありません。


フローチャートもずっと昔から書かなくなりました。
アセンブラは流石にブランチ命令は必須ですが…
歳が歳だけに、コーディングステップ数はアセンブラが一番多いです。
16ビット、32ビットやって最後に8ビットをやりました。

それでも1980年ころには構造化プログラミングは取り入れていて、フローチャートやgotoから縁が切れていました。
いや、Fortranの時にはgotoが復活しましたか。
C/C++ですとやはり細かく関数化したり、自分で自分を呼び出す再帰関数になりやすいです。
Lispをやっていた時には、doさえ使わず、繰り返しも全て再帰関数でやっていました。

勿論、オブジェクト指向がこの世に出た時には、これぞソフトウェア界の革命と呼べる技術だと思い、直ぐに取り入れました。

私は「誰にでも分かる」という言葉は無いと思っています。
プロに分かれば良いのです。
エラーが出難い設計、
開発効率のよい設計、
部品の再利用がしやすい設計、
などなどをとことん考え、勉強し、思想やノウハウを身につけた人にだけ分かれば良いのです。
しかも、何時までも更に良い方法がないかと、満足しない人ですね。プロとは。

オブジェクト指向をやっていると、多くの人が使い方や手順を覚えるだけで、意味を理解しようとする人が少いです。
これではオブジェクト指向は使わない方がマシなプログラムになるでしょう。
それでも私はオブジェクト指向です。
分からない人は、理解しようとしない人は置いてきぼりにされても仕方がないと考えます。
素人が足を引っ張ってレベルを下げることは、私には我慢出来ません。
    • good
    • 0

 No.4回答者さんが正解です。

構造化プログラミングです。再帰呼び出しも出来るように(自分から自分を呼び出す。)なります。
 ただメモリーマップドI/Oと思われますので切り替えてからある程度のディレイ時間が必要かも知れません。
 読み込みポート指定出力してからの時間をWRITE_DELAY_TIME,
 読み込んで次のポートを読み出す為の時間READ_DELAY_TIMEが必要かも知れませんので
 万が一に備えて#defineで宣言して変更し易くしておくのが良いかと思われます。
 Sleep()はスレッド停止時間が使用出来ればそのまま、使えないならForNextLoopでSleep()を新規に作成します。
 組み込みのハードウェアのタイミングについては質問者さんが一番ご存知だと思われますが。

#define WRITE_DELAY_TIME 0
#define READ_DELAY_TIME 0

int checkButton(){
int register=0;
p74 = High;
Sleep(WRITE_DELAY_TIME);
if(p70 == High){register ++;}
Sleep(READ_DELAY_TIME);
if(p71 == High){ register ++;}
Sleep(READ_DELAY_TIME);
if(p72 == High){ register ++;}
Sleep(READ_DELAY_TIME);
...
return (register == 1) ;
}

この回答への補足

今回の場合は、DO-WHILE文で代替ができそうです。
では、下記のような場合はどうでしょう。
N0.8さんが言われる「出口を一か所に集中させるにはgoto文を使う」です。
果たして、goto文を使わないでできるのでしょうか。

説明:
初めの10秒間でsw1が押されなかったらエラー処理1を実施して終了。
無事にsw1が押されると次の10秒がスタートする。
次の10秒間でsw2が押されなかったらエラー処理2を実施して終了。
無事にsw2が押されると次の次の10秒がスタートする。
次の次の10秒間でsw3が押されなかったらエラー処理3を実施して終了。


/*開始*/

int timer //型宣言 timerは1秒割込みで0になるまで1秒置きに-1されるものとする

timer = 10; // 10秒をセット
do{
____if(timer == 0){goto ERR_SYORI1;}
}while(sw1 == off)

timer = 10; // 10秒を再セット
do{
____if(timer == 0){goto ERR_SYORI2;}
}while(sw2 == off)


timer = 10; // 10秒を再セット
do{
____if(timer == 0){
________エラー処理3
ERR_SYORI2:
________エラー処理2
ERR_SYORI1:
________エラー処理1
________break;
____}
}while(sw3 == off)

/*終了*/

補足日時:2013/02/18 22:41
    • good
    • 0

私なら、こんな感じにすると思います



while(継続条件) {
if( checkButton() ) {
playSound();
}
}

そして、その流れ図のようなチェックをして、「音を鳴らしてはならない」なら0,「音を鳴らす」なら1を返す checkButton() 関数を作ります。
コードは、あなたが書いたのと似たのになりますが、
int checkButton(){
int register=0;
p74 = High;
if(p70 == High){register ++;}
if(p71 == High){ register ++;}
if(p72 == High){ register ++;}
...
return (register == 1) ;
}
と、gotoは使いませんし、KAISIへ戻ったりもしません。


さて、このプログラム、「わかりづらい」でしょうか?


gotoが害、というのは、構造化プログラミングという考え方から来たものです。
http://ja.wikipedia.org/wiki/%E6%A7%8B%E9%80%A0% …
現在主流のオブジェクト指向は、この構造化を発展させたものです。
現在主流の言語の多くは、goto文がありません。「ループからの脱出」等の特定の使い方に限定されたジャンプ命令(continue,break等)があるだけです。

では、どうするのか?
最初からgotoを使わない設計をします。

その記事をざっと斜め読みしましたが、初級者がアセンブリでプログラムしているようです。
Cでのif+gotoにあたる条件付分岐命令を使うことを念頭にフローチャートを作っているように思われます。
命令の少ないアセンブリでは、それが正しいやりかたかもしれません。
それをそのままCへ持ってこようとすれば、どうしてもgoto文を使いたくなります。

ですが、最初から、例えば構造化プログラミングを念頭に設計すれば、フローチャート自体が別なものになるでしょう。
goto文を使うことも無いはずです。

/* フローチャート自体も、最近のプログラミング設計には向かないと言われています */

この回答への補足

回答で書かれた文において、
最後の文の

return (register == 1) ;

はどういう意味でしょうか?
教えてください。
宜しくお願いします。

補足日時:2013/02/18 21:46
    • good
    • 0

私もdo~while()で書いちゃいますね。



やりたいことからすると、無駄が有るけどこんなかんじで。
____do {
________doremi = 0;
________register = 0;
________p74 = High;
________if(p70 == High) {
____________register++;
____________doremi = 1;
________}
________if(p71 == High) {
____________register++;
____________doremi = 2;
________}
________if(p72 == High) {
____________register++;
____________doremi = 3;
________}
________if(p73 == High) {
____________register++;
____________doremi = 4;
________}
________
________・
________
________・
________
________
____} while( register!=1 );
    • good
    • 0

私ならこう書きます。


まあ、do-while文も結構敬遠される書き方で、
do-whileにせざるを得ない設計は
他人のことを考えない悪い設計と私の職場なら言われかねません。

do{
 p74 = High;

 if(p70 == High){
  register = 1;
 }
 if(p71 != High){
  break;
 }
 register = register + 1;
}while(register != 1);

if(p72 == High){
 ・
 ・
    • good
    • 0

組み込み系という事で、企業などでPGをされている方だと仮定しますが、余所の人間がどうこう言おうと、職場の宗教に合わせるのが良いと思います。


(個人であれば、明日の自分の事を考えて使用頻度を見極めれば良いかと)

GOTOを使わないというのは、単に他人がそのソースをメンテするときに処理を追いにくくなるからであって、要はその他人がGOTOを追い切れる土壌にあるならばそれなりに使って構わないと思います。

ちなみに自分の職場ではGOTOの使用は『例え何があっても』御法度といった宗教で動いていますが(GOTOを使わなければ書けないアルゴリズムはそれ自体が間違っているとのこと)、自分でしかメンテしないモジュールには適度にGOTOを使っています。神の領域に逝ってしまった諸先輩の技量に合わせるために残業はしたくありませんので……。

GOTOを使えばステップ数もそれなりに減るのに、使わない為にIF文を8重くらいにネストしたコードを弄ったことがありますが、そこまで来ると別の弊害を感じました。そのくせやたらめったらグローバルに変数置いてたりして、一体どうなってるのかと。

要は、何事も適度がいいって事だと思います。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!