你能发一个真实的,过度的意大利面条代码的简短例子,可能会说它的作用是什么?你能告诉我一个小调试器的噩梦吗?
我不是指IOCCC代码,那是科幻小说.我的意思是发生在你身上的现实生活例子......
重点已从"发布一些意大利面条代码"到"什么是改变究竟面条代码?".从历史的角度来看,目前的选择似乎是:
旧的Fortran代码大量使用compute gotos
使用ALTER语句的旧Cobol代码
Brian Genisi.. 19
对我来说,一个更现代的意大利面条代码示例是当你有20个dll并且每个DLL以某种方式相互引用时.你的依赖图看起来像一个巨大的blob,你的代码在没有真正顺序的地方跳过.一切都是相互依赖的.
对我来说,一个更现代的意大利面条代码示例是当你有20个dll并且每个DLL以某种方式相互引用时.你的依赖图看起来像一个巨大的blob,你的代码在没有真正顺序的地方跳过.一切都是相互依赖的.
我不会把这个从头脑中拉出来.这是我必须使用的,虽然简化了.让我们说基本上你有一个需要枚举的程序:
enum { a, b, c; } myenum;
但相反,我们拥有的是
HashTable t; t["a"] = 0; t["b"] = 1; t["c"] = 2;
但是当然,没有哈希表的实现是足够好的,因此有一个哈希表的本地实现,其中包含的代码大约是平均开源实现的10倍,具有一半的功能和错误数量的两倍.HashTable实际上是虚拟定义的,并且有一个工厂HashTableFactory来创建HashTables的实例,但是HashTableFactory模式也是虚拟的.为了防止虚拟类的infite级联,有一个功能
HashTableFactory *makeHashTableFactor();
因此,代码需要myenum的所有地方都带有对HashTable和HashTableFactory实例的引用,以防你想要制作更多的HashTable.但等等,这不是全部!这不是哈希表的初始化方式,而是通过编写读取XML的代码来完成的:
并插入哈希表.但代码是"优化的",因此它不会读取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); }
我们已经生成了数千行代码(私有新的,错误的,复杂的,哈希表的实现,以及xml阅读器和编写器)来代替上面的3个代码.
还有Ravioli Code,相反.漂亮的小块功能,干净的界面整齐地包裹着肉质的美味,都坐在一个漂亮的框架酱.
从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
输出是一系列行列出文件,按照不同标签的数量排序,如下所示:
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
真正的意大利面条代码在COBOL中完成并使用了ALTER语句.
这是一个例子,虽然列出了一个"幽默",但我已经看到了这种事情.因为注意到任何带有Alter声明的程序显然都处于犯罪状态,所以几乎被解雇了一次.我拒绝"维护"该程序,更换它比理解它更快.
别忘了提到面向对象的意大利面条.这是当你尝试使用书中的所有设计模式时,即使它们没有意义.这导致概念级别的意大利面条代码,这比传统的基于goto的意大利面条代码更不利于质量.
你问过它,你会得到它:
这是播放蓝色多瑙河华尔兹的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
真正的意大利面条代码需要大量的非本地代码.遗憾的是,使用大多数现代语言是不可能的.
编辑:有人建议将例外和longjmp作为GOTO的替代品.但这些都远远有限和结构,因为它们只允许您返回了调用堆栈.真正的GOTO允许您跳转到程序中任何位置的任何行,这是创建真正的意大利面条所必需的.
简单来说,意大利面条代码是任何编程语言中的任何代码,其中不可能跟踪下一个执行的帖子,或者至少难以确定下一个点在一个动作的响应中的位置.