什么是意大利面条代码?

发布于 2024-07-06 09:25:23 字数 1453 浏览 5 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

停顿的约定 2024-07-13 09:25:23

对我来说,意大利面条式代码的一个更现代的示例是,当您有 20 个 DLL,并且每个 DLL 以一种或另一种方式相互引用时。 您的依赖关系图看起来像一个巨大的斑点,并且您的代码到处乱跳,没有真正的顺序。 一切都是相互依存的。

To me, a more modern example of spaghetti code is when you have 20 dlls and every DLL references each other in one way or another. Your dependency graph looks like a huge blob, and your code hops all over the place with no real order. Everything is inter-dependent.

汹涌人海 2024-07-13 09:25:23

我不会把这件事从我的脑海中抹去。 这就是我必须处理的问题,尽管很简单。 假设基本上你有一个需要枚举的程序:

enum {
   a, b, c;
} myenum;

但是我们拥有的是

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

但是当然,哈希表的实现都不够好,所以有一个哈希表的本地实现,它包含的代码大约是 10 倍一个普通的开源实现,其功能只有一半,但错误数量却增加了一倍。 HashTable 实际上是定义为虚拟的,并且有一个工厂 HashTableFactory 来创建 HashTable 的实例,但按照模式 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);

Ok ,所以我们有很多代码来获取枚举结构。 它基本上用在一个函数中:

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。

I'm not pulling this out of my head. This is what I have had to work with, albeit simplified. Let's say that basically you have a program that needs an enum:

enum {
   a, b, c;
} myenum;

But instead what we have is

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

But of course, no implementation of a hash table is good enough so there is a local implementation of hash tables, which contains about 10 times more code than an average open source implementation with half the features and double the number of bugs. The HashTable is actually defined virtual, and there's a factory HashTableFactory to create instances of HashTables, but true to the pattern HashTableFactory is also virtual. To prevent an infite cascade of virtual classes there's a function

HashTableFactory *makeHashTableFactor();

Thus everywhere where the code needs myenum's it carries a reference to the instance of a HashTable and HashTableFactory, in case you want to make more HashTable's. But wait, that's not all! This is not how the hash table is initialized, but it's done by writing a code that reads XML:

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

and inserts into a hash table. But the code is "optimised" so that it doesn't read an ascii file myenum.xml, but instead there's a compile time script which generates:

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

from myenum.xml and the hash table is initialized by a function:

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

which is called:

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

Ok, so we have a lot of code to get an enum structure. It's basically used in a function:

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

and this is called in a context where:

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

So what we actually have is instead of

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

we have manged to generate thousands of lines of code (private new, buggy, complex, implementation of hashtables, and xml readers, and writer) in place of the above 3.

梦忆晨望 2024-07-13 09:25:23

还有Ravioli Code,这是相反的。 漂亮的小块功能,干净的界面整齐地包裹着丰富的优点,所有这些都位于一个很好的框架中。

There's also Ravioli Code, which is the opposite. Nice little chunks of functionality, a clean interface neatly wrapped around meaty goodness, all sat in a nice sauce of framework.

恍梦境° 2024-07-13 09:25:23

来自 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#,       */

我是如何找到这个 gem 的?

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

From a Linux SCSI driver (which shall remain nameless to protect the guilty):

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#,       */

How did I locate this gem?

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

The output is a series of lines listing files ordered by the number of gotos to distinct labels, like the following:

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
匿名的好友 2024-07-13 09:25:23

不要忘记提及面向对象的意大利面条。
这是当你尝试使用书中的所有设计模式时,即使它们没有意义。 这会导致概念层面上的意大利面条式代码,这比传统的基于 goto 的意大利面条式代码对质量的影响要大得多。

Don't forget to mention Object-oriented spaghetti.
This is when you try to use all the design patterns in the book, even when they don't make sense. This leads to spaghetti code at conceptual level, which is far more detrimental to quality than classical goto-based spaghetti code.

久光 2024-07-13 09:25:23

真正的意大利面条代码是用 COBOL 完成的,并使用了 ALTER 语句。

这是一个示例,虽然列出了“幽默”,但我见过这种事情。 有一次差点因为注意到任何带有 Alter 语句的程序显然处于罪恶状态而被解雇。 我拒绝“维护”该程序,替换它比理解它更快。

Real spaghetti code was done in COBOL and used the ALTER statement.

Here's an example, while listed a "humor", I've seen this kind of thing. Almost got fired once for noting that any program with an Alter statement was obviously in a state of sin. I refused to "maintain" that program, it was quicker to replace it than understand it.

别再吹冷风 2024-07-13 09:25:23

你已经要求它,你就会得到它:

这是播放蓝色多瑙河华尔兹的 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

You've asked for it, you'll get it:

This is the source of a DOS .com file that plays the Blue Danube waltz. The executable is just 176 bytes in size. Code is re-used as data and vice versa.

.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
故乡的云 2024-07-13 09:25:23

真实意大利面条代码需要大量非本地 goto。 遗憾的是,使用大多数现代语言这是不可能的。

编辑:有些人建议使用例外和 longjmp 作为 GOTO 的替代品。 但这些远远受到限制和结构化,因为它们只允许您返回调用堆栈。 真正的 GOTO 允许您跳转到程序中的任何任何地方,这是创建真正的意大利面条所必需的。

Real spaghetti-code requires a multitude of non-local gotos. Sadly this is not possible using most modern languages.

Edit: Some suggest exceptions and longjmp as substitutes for GOTO. But these are far to limited and structured, since they only allow you to return up the callstack. Real GOTO allows you to jump to any line anywhere in the program, which is necessary to create real spaghetti.

卖梦商人 2024-07-13 09:25:23

简单来说,意大利面条代码是任何编程语言中的任何代码,其中不可能跟踪下一个执行过程,或者至少难以确定响应一个操作的下一个点的位置。

In simple terms spaghetti code is any code in any programming language in which it is not possible to trace the next post of execution, or at least difficult to determine where the next point goes in response of one action.

站稳脚跟 2024-07-13 09:25:23

这是我之前写的一个 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;
            }
        }
    }
}

This is from a MIDI parser I wrote some time ago. It was a quick and dirty proof of concept, but nevertheless, I shall take the blame for its ugliness: 4 levels of nested conditionals plus the dreaded multiple returns. This code was meant to compare 2 MIDI events in order to sort them by priority when writing to a file. Ugly as it was, it did the job decently, though.

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;
            }
        }
    }
}
寄人书 2024-07-13 09:25:23

这是 Duff 的设备,来自 Matt 对 这个问题

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);
}

Here is the Duff's Device, from Matt's answer to this question:

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);
}
不再让梦枯萎 2024-07-13 09:25:23

意大利面条代码:意大利面条代码起源于 60 年代初的意大利,作为某些意大利面食的替代食谱,由一位餐厅企业家发明,他试图自动创建一道万无一失的主菜。 由于缺乏时间来完成设计,工程师/厨师偷工减料,这在早期的配方中引入了问题。 为了弥补一个坏主意的疯狂尝试,随着配方失控,各种香料很快被添加到混合物中。 结果是一堆冗长、曲折但可能很美味的文本,后来成为全世界开发人员所珍视的做法。

Spaghetti code: Originating in the early 60's in Italy as an alternate recipe for certain pasta dishes, spaghetti code was cooked up by one restaurant entrepreneur who attempted to automate the creation of a fool-proof entree. Pressed by the lack of time to complete the design the engineer/chef cut corners which introduced problems in the recipe early on. In a frantic attempt to remedy a good idea gone bad, various spices were quickly added to the concoction as the recipe grew out of control. The result was a stringy, twisty, yet potentially tasty pile of text that would later grow to be a practice cherished by developers world-wide.

陌若浮生 2024-07-13 09:25:23

您是否看过 Flex/Bison 扫描器和生成器生成的代码? 大量标签和预处理器指令。

绝对不可能理解里面的内容......并且绝对不可能遵循程序的流程。

这绝对是意大利面条式的代码。

Have you ever looked at code generated by Flex/Bison scanner and generator? A plethora of labels and preprocessor directives.

It's absolutely impossible to understand what's inside.. and absolutely impossible to follow flow of the program.

That's definetely spaghetti code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文