Fed*_*oni 25 terminology anti-patterns
你能发一个真实的,过度的意大利面条代码的简短例子,可能会说它的作用是什么?你能告诉我一个小调试器的噩梦吗?
我不是指IOCCC代码,那是科幻小说.我的意思是发生在你身上的现实生活例子......
重点已从"发布一些意大利面条代码"到"什么是改变究竟面条代码?".从历史的角度来看,目前的选择似乎是:
Bri*_*sio 19
对我来说,一个更现代的意大利面条代码示例是当你有20个dll并且每个DLL以某种方式相互引用时.你的依赖图看起来像一个巨大的blob,你的代码在没有真正顺序的地方跳过.一切都是相互依赖的.
小智 15
我不会把这个从头脑中拉出来.这是我必须使用的,虽然简化了.让我们说基本上你有一个需要枚举的程序:
enum {
a, b, c;
} myenum;
Run Code Online (Sandbox Code Playgroud)
但相反,我们拥有的是
HashTable t;
t["a"] = 0;
t["b"] = 1;
t["c"] = 2;
Run Code Online (Sandbox Code Playgroud)
但是当然,没有哈希表的实现是足够好的,因此有一个哈希表的本地实现,其中包含的代码大约是平均开源实现的10倍,具有一半的功能和错误数量的两倍.HashTable实际上是虚拟定义的,并且有一个工厂HashTableFactory来创建HashTables的实例,但是HashTableFactory模式也是虚拟的.为了防止虚拟类的infite级联,有一个功能
HashTableFactory *makeHashTableFactor();
Run Code Online (Sandbox Code Playgroud)
因此,代码需要myenum的所有地方都带有对HashTable和HashTableFactory实例的引用,以防你想要制作更多的HashTable.但等等,这不是全部!这不是哈希表的初始化方式,而是通过编写读取XML的代码来完成的:
<enum>
<item name="a" value="0"/>
<item name="b" value="1"/>
<item name="c" value="2"/>
</enum>
Run Code Online (Sandbox Code Playgroud)
并插入哈希表.但代码是"优化的",因此它不会读取ascii文件myenum.xml,而是有一个编译时脚本生成:
const char* myenumXML = [13, 32, 53 ....];
Run Code Online (Sandbox Code Playgroud)
来自myenum.xml,哈希表由函数初始化:
void xmlToHashTable(char *xml, HashTable *h, HashTableFactory *f);
Run Code Online (Sandbox Code Playgroud)
这就是所谓的:
HashTableFactory *factory = makeHashTableFactory();
HashTable *t = facotry.make();
xmlToHashTable(myenumXML, t, f);
Run Code Online (Sandbox Code Playgroud)
好的,所以我们有很多代码来获得枚举结构.它基本上用在一个函数中:
void printStuff(int c) {
switch (c) {
case a: print("a");
case b: print("b");
case c: print("c");
}
}
Run Code Online (Sandbox Code Playgroud)
这在以下情况下调用:
void stuff(char* str) {
int c = charToEnum(str);
printStuff(c);
}
Run Code Online (Sandbox Code Playgroud)
所以我们实际拥有的不是
void stuff(char *str) {
printf(str);
}
Run Code Online (Sandbox Code Playgroud)
我们已经生成了数千行代码(私有新的,错误的,复杂的,哈希表的实现,以及xml阅读器和编写器)来代替上面的3个代码.
从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#, */
Run Code Online (Sandbox Code Playgroud)
我是如何找到这颗宝石的?
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
Run Code Online (Sandbox Code Playgroud)
输出是一系列行列出文件,按照不同标签的数量排序,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
你问过它,你会得到它:
这是播放蓝色多瑙河华尔兹的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
Run Code Online (Sandbox Code Playgroud)
真正的意大利面条代码需要大量的非本地代码.遗憾的是,使用大多数现代语言是不可能的.
编辑:有人建议将例外和longjmp作为GOTO的替代品.但这些都远远有限和结构,因为它们只允许您返回了调用堆栈.真正的GOTO允许您跳转到程序中任何位置的任何行,这是创建真正的意大利面条所必需的.