32

実際のやり過ぎたスパゲッティ コードの短い例を投稿していただけますか? デバッガーの悪夢を少し見せてもらえますか?

IOCCCコードのことではありません。それは SF です。私はあなたに起こった実際の例を意味します...

アップデート

焦点は、「スパゲッティ コードを投稿する」から「スパゲッティ コードとは正確には何ですか?」に変わりました。歴史的な観点から、現在の選択肢は次のように思われます。

  • 計算された goto を大量に使用する古い Fortran コード
  • ALTER ステートメントを使用する古い COBOL コード
4

13 に答える 13

28

私にとって、スパゲッティ コードのより現代的な例は、20 個の dll があり、すべての DLL が何らかの方法で相互に参照している場合です。依存関係グラフは巨大なブロブのように見え、コードは実際の順序であちこち飛び回っています。すべては相互依存です。

于 2008-11-28T13:35:57.660 に答える
21

私はこれを頭から引き離していません。これは、単純化されていますが、私が取り組まなければならなかったものです。基本的に列挙型を必要とするプログラムがあるとしましょう:

enum {
   a, b, c;
} myenum;

しかし、代わりに私たちが持っているのは

HashTable t;
t["a"] = 0;
t["b"] = 1;
t["c"] = 2;

しかしもちろん、ハッシュ テーブルの実装だけでは十分ではないため、ハッシュ テーブルのローカル実装があります。これには、平均的なオープン ソース実装の約 10 倍のコードが含まれ、機能は半分で、バグの数は 2 倍になります。HashTable は実際には仮想として定義されており、HashTable のインスタンスを作成するためのファクトリ HashTableFactory がありますが、パターンに当てはまれば HashTableFactory も仮想です。仮想クラスの無限のカスケードを防ぐために、関数があります

HashTableFactory *makeHashTableFactor();

したがって、コードがmyenumを必要とするところはどこでも、HashTable と HashTableFactory のインスタンスへの参照を運ぶので、さらに HashTable を作成したい場合に備えます。しかし、待ってください。それだけではありません。これは、ハッシュ テーブルが初期化される方法ではありませんが、XML を読み取るコードを記述することによって行われます。

<enum>
  <item name="a" value="0"/>
  <item name="b" value="1"/>
  <item name="c" value="2"/>
</enum>

ハッシュテーブルに挿入します。しかし、コードは ascii ファイル myenum.xml を読み取らないように「最適化」されていますが、代わりに次を生成するコンパイル時スクリプトがあります。

const char* myenumXML = [13, 32, 53 ....];

myenum.xml から、ハッシュ テーブルは次の関数によって初期化されます。

void xmlToHashTable(char *xml, HashTable *h, HashTableFactory *f);

これは次のように呼ばれます:

HashTableFactory *factory = makeHashTableFactory();
HashTable *t = facotry.make();
xmlToHashTable(myenumXML, t, f);

さて、列挙型構造を取得するためのコードがたくさんあります。基本的に関数で使用されます:

void printStuff(int c) {
   switch (c) {
   case a: print("a");
   case b: print("b");
   case c: print("c");
   }
}

これは、次のコンテキストで呼び出されます。

void stuff(char* str) {
   int c = charToEnum(str);
   printStuff(c);
}

だから私たちが実際に持っているのは代わりに

void stuff(char *str) {
   printf(str);
}

上記の 3 の代わりに、数千行のコード (非公開、バグ、複雑、ハッシュテーブルの実装、xml リーダー、およびライター) を生成することができました。

于 2010-07-28T13:49:12.937 に答える
18

反対のラビオリコードもあります。素敵な機能の塊、肉の良さをきれいに包んだきれいなインターフェース、すべてが素敵なフレームワークのソースに収まっています.

于 2008-11-28T13:47:51.147 に答える
10

実際のスパゲッティコードはCOBOLで実行され、ALTERステートメントを使用しました。

ここにがあります、「ユーモア」をリストしている間、私はこの種のものを見ました。Alterステートメントを含むプログラムが明らかに罪の状態にあることに気付いたためにほとんど一度解雇されました。私はそのプログラムを「維持」することを拒否しました、それを理解するよりもそれを置き換える方が迅速でした。

于 2008-10-12T15:57:01.297 に答える
10

Linux SCSI ドライバー (有罪を保護するために無名のままにする必要があります) から:

wait_nomsg:
        if ((inb(tmport) & 0x04) != 0) {
                goto wait_nomsg;
        }
        outb(1, 0x80);
        udelay(100);
        for (n = 0; n < 0x30000; n++) {
                if ((inb(tmport) & 0x80) != 0) {        /* bsy ? */
                        goto wait_io;
                }
        }
        goto TCM_SYNC;
wait_io:
        for (n = 0; n < 0x30000; n++) {
                if ((inb(tmport) & 0x81) == 0x0081) {
                        goto wait_io1;
                }
        }
        goto TCM_SYNC;
wait_io1:
        inb(0x80);
        val |= 0x8003;          /* io,cd,db7  */
        outw(val, tmport);
        inb(0x80);
        val &= 0x00bf;          /* no sel     */
        outw(val, tmport);
        outb(2, 0x80);
TCM_SYNC:
/* ... */
small_id:
        m = 1;
        m <<= k;
        if ((m & assignid_map) == 0) {
                goto G2Q_QUIN;
        }
        if (k > 0) {
                k--;
                goto small_id;
        }
G2Q5:                   /* srch from max acceptable ID#  */
        k = i;                  /* max acceptable ID#            */
G2Q_LP:
        m = 1;
        m <<= k;
        if ((m & assignid_map) == 0) {
                goto G2Q_QUIN;
        }
        if (k > 0) {
                k--;
                goto G2Q_LP;
        }
G2Q_QUIN:               /* k=binID#,       */

どうやってこの宝石を見つけたのですか?

find /usr/src/linux -type f -name \*.c | 
while read f
do 
    echo -n "$f "
    sed -n 's/^.*goto *\([^;]*\);.*/\1/p' $f | sort -u | wc -l
done | 
sort +1rn |
head

出力は、次のように、異なるラベルへの goto の数によって順序付けられたファイルをリストする一連の行です。

kernel/fork.c 31
fs/namei.c 35
drivers/infiniband/hw/mthca/mthca_main.c 36
fs/cifs/cifssmb.c 45
fs/ntfs/super.c 47
于 2008-10-12T14:36:56.997 に答える
9

オブジェクト指向のスパゲッティについて言及することを忘れないでください。これは、本に書かれているすべてのデザイン パターンを、意味をなさない場合でも使用しようとする場合です。これは概念レベルでのスパゲッティ コードにつながり、従来の goto ベースのスパゲッティ コードよりもはるかに品質に悪影響を及ぼします。

于 2009-03-05T14:32:43.470 に答える
8

あなたはそれを求めました、あなたはそれを手に入れるでしょう:

これは、青きドナウのワルツを演奏する DOS .com ファイルのソースです。実行可能ファイルのサイズはわずか 176 バイトです。コードはデータとして再利用され、その逆も同様です。

.286
.model tiny

g4 equ 55-48           ; removed note-decoding !
a4 equ 57-48           ; now: storing midi-notes for octaves 0..2 and convert
h4 equ 59-48           ; to 4..6 with a simple add 48.

c5 equ 60-48
d5 equ 62-48
e5 equ 64-48
g5 equ 67-48
h5 equ 71-48

c6 equ 72-48
d6 equ 74-48
e6 equ 76-48
g6 equ 79-48           ; = 00011111b

pp  equ 0              ;  c4 is not used in the walz, using it as play-pause.
EOM equ 1              ; c#4 is also available... End Of Music
                       ; warning: experts only beyond this point !

pau1 equ 00100000b     ; bitfield definitions for note-compression
pau2 equ 01000000b     ; you can or a pau to each note!
pau3 equ 01100000b

;rep1 equ 01000000b    ; rep1 is history (only used once).
;rep3 equ 11000000b    ; rep3 was never used.

rep2 equ 10000000b     ; or a rep2 to a note to play it 3 times.

drumsize equ 5

.code
org 100h

start:
                mov  ah,9
                mov  dx,offset msg
                int  21h                    ; print our headerstring

                mov  dx,0330h               ; gus midi megaem -port
                mov  si,offset music_code   ; start of music data

mainloop:

    ; get new note (melody)

                xor  bp,bp                  ; bp= repeat-counter

                lodsb                       ; get a new note
                cmp  al, EOM                ; check for end
                jne  continue
                ret

continue:
                jns  no_rep2                ; check for rep2-Bit
                inc  bp
                inc  bp                     ; "build" repeat-counter

no_rep2:
                push ax                     ; save the note for pause

    ; "convert" to midi-note

                and  al,00011111b
                jz   skip_pp                ; check pp, keep it 0
                add  al,48                  ; fix-up oktave

skip_pp:
                xchg ax,bx                  ; bl= midi-note

play_again:
                mov  cl,3
                push cx                     ; patch program (3= piano)
                push 0c8h                   ; program change, channel 9

    ; wait (cx:dx) times

                mov  ah,86h                 ; wait a little bit
                int  15h

    ; prepare drums

                dec  di                     ; get the current drum
                jns  no_drum_underflow
                mov  di,drumsize

no_drum_underflow:

    ; play drum

                push dx                     ; volume drum
                push [word ptr drumtrk+di]  ; note   drum
                mov  al,99h
                push ax                     ; play channel 10

    ; play melody

                push dx                     ; volume melody
                push bx                     ; note   melody

                dec  ax                     ; replaces dec al :)

                push ax                     ; play channel 9

    ; send data to midi-port

                mov  cl,8                   ; we have to send 8 bytes

play_loop:
                pop  ax                     ; get the midi event
                out  dx,al                  ; and send it
                loop play_loop

    ; repeat "bp" times

                dec  bp                     ; repeat the note
                jns  play_again

    ; check and "play" pause

                xor  bx,bx                  ; clear the note, so we can hear
                                            ; a pause
    ; decode pause value

                pop  ax
                test al,01100000b
                jz   mainloop               ; no pause, get next note

    ; decrement pause value and save on stack

                sub  al,20h
                push ax
                jmp  play_again             ; and play next drum

; don't change the order of the following data, it is heavily crosslinked !
music_code      db pp or rep2

                db g4 or rep2 or pau1
                db h4 or pau1, d5 or pau1, d5 or pau3
                db d6 or pau1, d6 or pau3, h5 or pau1, h5 or pau3

                db g4 or rep2 or pau1
                db h4 or pau1, d5 or pau1, d5 or pau3
                db d6 or pau1, d6 or pau3, c6 or pau1, c6 or pau3

                db a4 or rep2 or pau1
                db c5 or pau1, e5 or pau1, e5 or pau3
                db e6 or pau1, e6 or pau3, c6 or pau1, c6 or pau3

                db a4 or rep2 or pau1
                db c5 or pau1, e5 or pau1, e5 or pau3
                db e6 or pau1, e6 or pau3, h5 or pau1, h5 or pau3

                db g4 or rep2 or pau1
                db h4 or pau1, g5 or pau1, g5 or pau3
                db g6 or pau1, g6 or pau3, d6 or pau1, d6 or pau3

                db g4 or rep2 or pau1
                db h4 or pau1, g5 or pau1, g5 or pau3
                db g6 or pau1, g6 or pau3, e6 or pau1, e6 or pau3

                db a4 or rep2 or pau1
                db c5 or pau1, e5 or pau1, e5 or pau3, pp or pau3
                db c5 or pau1, e5 or pau1, h5 or pau3, pp or pau3, d5 or pau1

                db h4 or pau1, h4 or pau3
                db a4 or pau1, e5 or pau3
                db d5 or pau1, g4 or pau2

;                db g4 or rep1 or pau1
; replace this last "rep1"-note with two (equal-sounding) notes
                db g4
                db g4 or pau1

msg             db EOM, 'Docking Station',10,'doj&sub'
drumtrk         db 36, 42, 38, 42, 38, 59  ; reversed order to save some bytes !

end start
于 2008-10-12T14:12:50.773 に答える
7

簡単に言うと、スパゲッティコードとは、次の実行ポストを追跡できない、または少なくとも1つのアクションに応じて次のポイントがどこに行くのかを判断するのが難しいプログラミング言語のコードです。

于 2013-02-21T09:29:58.230 に答える
7

実際のスパゲッティ コードでは、多数のローカル以外の goto が必要です。残念ながら、これはほとんどの現代言語では不可能です。

編集:GOTOの代わりに例外とlongjmpを提案する人もいます。しかし、コールスタックを返すことしかできないため、これらは限定的で構造化されているとは言えませんReal GOTO を使用すると、プログラム内の任意の行にジャンプできますこれは、実際のスパゲッティを作成するために必要です。

于 2008-10-12T14:07:05.357 に答える
4

これは、私が以前に書いた MIDI パーサーからのものです。これは手早く汚い概念実証でしたが、それでも、その醜さの責任は私にあります。4 レベルのネストされた条件文と恐ろしい複数の戻り値です。このコードは、ファイルへの書き込み時に 2 つの MIDI イベントを比較して優先度順に並べ替えるためのものです。醜いものでしたが、きちんと仕事をしました。

internal class EventContainerComparer : IComparer {

    int IComparer.Compare(object a, object b) {
        MIDIEventContainer evt1 = (MIDIEventContainer) a;
        MIDIEventContainer evt2 = (MIDIEventContainer) b;

        ChannelEvent chanEvt1;
        ChannelEvent chanEvt2;

        if (evt1.AbsoluteTime < evt2.AbsoluteTime) {
            return -1;
        } else if (evt1.AbsoluteTime > evt2.AbsoluteTime) {
            return 1;
        } else {    
            // a iguar valor de AbsoluteTime, los channelEvent tienen prioridad
            if(evt1.MidiEvent is ChannelEvent && evt2.MidiEvent is MetaEvent) {
                return -1;
            } else if(evt1.MidiEvent is MetaEvent && evt2.MidiEvent is ChannelEvent){
                return 1;
            //  si ambos son channelEvent, dar prioridad a NoteOn == 0 sobre NoteOn > 0
            } else if(evt1.MidiEvent is ChannelEvent && evt2.MidiEvent is ChannelEvent) {

                chanEvt1 = (ChannelEvent) evt1.MidiEvent;
                chanEvt2 = (ChannelEvent) evt2.MidiEvent;

                // si ambos son NoteOn
                if( chanEvt1.EventType == ChannelEventType.NoteOn 
                    && chanEvt2.EventType == ChannelEventType.NoteOn){

                    //  chanEvt1 en NoteOn(0) y el 2 es NoteOn(>0)
                    if(chanEvt1.Arg1 == 0 && chanEvt2.Arg1 > 0) {
                        return -1;
                    //  chanEvt1 en NoteOn(0) y el 2 es NoteOn(>0)
                    } else if(chanEvt2.Arg1 == 0 && chanEvt1.Arg1 > 0) {
                        return 1;
                    } else {
                        return 0;
                    }
                // son 2 ChannelEvent, pero no son los 2 NoteOn, el orden es indistinto
                } else {
                    return 0;
                }
            //  son 2 MetaEvent, el orden es indistinto
            } else {
                return 0;
            }
        }
    }
}
于 2008-10-13T17:00:06.207 に答える
3

この質問に対するマットの回答からのダフのデバイスは次のとおりです。

int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7:      *to = *from++;
case 6:      *to = *from++;
case 5:      *to = *from++;
case 4:      *to = *from++;
case 3:      *to = *from++;
case 2:      *to = *from++;
case 1:      *to = *from++;
           } while (--n > 0);
}
于 2008-11-28T13:27:51.280 に答える
0

スパゲッティコード:60年代初頭に特定のパスタ料理の代替レシピとしてイタリアで生まれたスパゲッティコードは、誰にでもできるメインディッシュの作成を自動化しようとしたあるレストランの起業家によって作成されました。設計を完了するための時間の不足に押されて、エンジニア/シェフは早い段階でレシピに問題をもたらした角を切りました。良いアイデアが悪くなったのを直すための必死の試みで、レシピが制御不能になるにつれて、さまざまなスパイスがすぐに調合に追加されました。その結果、糸を引く、ねじれた、しかし潜在的においしいテキストの山ができ、後に世界中の開発者が大事にする慣習になりました。

于 2008-10-12T17:37:52.373 に答える