2016-07-19 3 views
1

Ich arbeite an schrecklichen Code.Vergleichen von Code-Implementierungen, GCC, wenn/else-> weiter

while (x) 
{ 
    if (check1) 
    { 
     if (check2) 
     { 
      if (check3) 
      { 
       function(); 
      } 
      else 
      { 
       error3(); 
      } 
     } 
     else 
     { 
      error2(); 
     } 
    } 
    else 
    { 
     error1(); 
    } 
} 

Ich würde es gerne mögen dieses

while (x) 
{ 
    if (!check1) 
    { 
     error1(); 
     continue; 
    } 
    if (!check2) 
    { 
     error2(); 
     continue; 
    } 
    if (!check3) 
    { 
     error3(); 
     continue; 
    } 
    function(); 
} 

aussehen, aber ... Das ist 'Zeit getestet Code', die in vielen Produkten ist ..... ... und schrecklich mit zu arbeiten und wird Fehler in der Zukunft fördern.

Ich brauche einen Weg zu beweisen, dass, wenn ich den Code zu meiner Implementierung ändern, der resultierende Code gleichwertig ist.

Gerade jetzt, wenn ich die beiden Versionen von Code kompiliere, bekomme ich verschiedene Binärdateien.

Fragen:

Gibt es eine Möglichkeit, den Compiler zu ermutigen, die gleiche Leistung für beide Implementierungen zu bekommen, so dass ich Management nachweisen können, dass sie das gleiche sind?

Gibt es eine andere Möglichkeit zu demonstrieren, dass die Implementierungen äquivalent sind?

+4

Sie brauchen nicht von th Ose Continue-Anweisungen: 'if (! check1) error1(); sonst if (! check2) error2(); sonst falls (! check3) error3(); else function(); 'arbeitet prägnanter und klarer. –

+0

Kernighan & Plauger in "Die Elemente des Programmierstils" sagen etwas in der Art von "Nachdem Sie eine Bedingung getestet haben, tun Sie etwas" (was bedeutet "teste nicht eine andere Bedingung"). –

+1

Ich stimme nicht zu, dass es klarer ist, ohne 'continue's. Es sagt explizit, dass ich zurück zum Anfang der "while" -Schleife gehe, anstatt nach unten zu scrollen, um zu überprüfen, ob es etwas außerhalb des else gibt, wenn ... Ich denke, dass "continue" ein ist nützliches Werkzeug, vor dem viele Angst haben. Entschuldigung, mein Beispielcode ist kurz, der eigentliche Code kaskadiert über 10 Mal und Sie können den unteren Teil der Schleife nicht auf einem einzigen Bildschirm sehen. Deshalb bin ich eher geneigt, das 'continue' –

Antwort

2

Es wird erwartet, dass Sie verschiedene Binärdateien erhalten.

Obwohl es einfach ist, diese Änderung nur durch eine Codeüberprüfung zu überprüfen, können Sie auch Komponententests ausführen, um die Ergebnisse für alle möglichen Eingabebedingungen zu validieren und zu beweisen, dass die Ergebnisse übereinstimmen und auch alle Komponententests bestanden werden. Dies ist der Fall, wenn Sie eine vollständige Codeabdeckung durch die Komponententests sicherstellen können.

Stimmen Sie mit Jonathans Kommentar über die Vermeidung von Continue-Anweisungen überein.

2

Da Sie nur drei Prüfungen haben, gibt es nur 2^3 = 8 verschiedene Fälle zu prüfen. Und alles, was Sie überprüfen müssen, ist, dass die beiden Lösungen in jedem der 8 Fälle dieselbe Funktion aufrufen.

Alles, was Sie tun müssen, ist, alle 8 Möglichkeiten anzuwenden und den Namen der aufgerufenen Funktion auszudrucken. Etwas wie:

#include <stdio.h> 

void f(void) {printf("f \n");} 
void e1(void) {printf("e1 \n");} 
void e2(void) {printf("e2 \n");} 
void e3(void) {printf("e3 \n");} 


void original_logic() 
{ 
    int x = 7; 
    int c1, c2, c3; 
    printf("original_logic:\n"); 
    printf("c3 c2 c1 -> calls\n"); 
    while(x >= 0) 
    { 
    c1 = ((x & 0x1) == 0); 
    c2 = ((x & 0x2) == 0); 
    c3 = ((x & 0x4) == 0); 
    x--; 
    printf(" %d %d %d -> ", c3, c2, c1); 

    // Logic from original code 
    if (c1) 
    { 
     if (c2) 
     { 
     if (c3) 
     { 
      f(); 
     } 
     else 
     { 
      e3(); 
     } 
     } 
     else 
     { 
     e2(); 
     } 
    } 
    else 
    { 
     e1(); 
    } 
    } 
} 

void modified_logic() 
{ 
    int x = 7; 
    int c1, c2, c3; 
    printf("modified_logic:\n"); 
    printf("c3 c2 c1 -> calls\n"); 
    while(x >= 0) 
    { 
    c1 = ((x & 0x1) == 0); 
    c2 = ((x & 0x2) == 0); 
    c3 = ((x & 0x4) == 0); 
    x--; 
    printf(" %d %d %d -> ", c3, c2, c1); 

    // Logic from modified code 
    if (!c1) 
    { 
     e1(); 
     continue; 
    } 
    if (!c2) 
    { 
     e2(); 
     continue; 
    } 
    if (!c3) 
    { 
     e3(); 
     continue; 
    } 
    f(); 
    } 
} 

int main() 
{ 
    original_logic(); 
    modified_logic(); 
    return 0; 
} 

welche folgende Ausgabe:

original_logic: 
c3 c2 c1 -> calls 
0 0 0 -> e1 
0 0 1 -> e2 
0 1 0 -> e1 
0 1 1 -> e3 
1 0 0 -> e1 
1 0 1 -> e2 
1 1 0 -> e1 
1 1 1 -> f 
modified_logic: 
c3 c2 c1 -> calls 
0 0 0 -> e1 
0 0 1 -> e2 
0 1 0 -> e1 
0 1 1 -> e3 
1 0 0 -> e1 
1 0 1 -> e2 
1 1 0 -> e1 
1 1 1 -> f 

Da die beiden Tabellen identisch sind, wissen Sie die Logik identisch ist.

+0

Dieser Code ist nur Pseudocode, um die Situation zu erklären, gibt es mehr, und sie sind nicht so einfach wie Dies erscheint. –

+0

@ mr_guy99493 - nun, selbst mit 16 logischen Variablen ist es immer noch möglich, innerhalb einer angemessenen Zeit alle 2^16 Kombinationen zu überprüfen, die Ausgabe in Dateien zu pipettieren und einen Dateivergleich durchzuführen. Wenn die Struktur des Codes anders als die gezeigte ist ... Hmm, es ist ziemlich schwierig, eine nützliche Antwort über nicht gezeigten Code zu geben :-) – 4386427

0

Ich habe einen Alternativvorschlag:

  • Es verwendet einen einzelnen Zweig (switch) anstelle von mehreren Zweigen (if)
  • Es Sie jede mögliche Kombination Ihrer check Variablen
leicht zu handhaben erlaubt
while (x) 
{ 
    #define COMBINATION(a,b,c) ((a? (1<<2):0)|(b? (1<<1):0)|(c? (1<<0):0)) 
    switch (COMBINATION(check1,check2,check3)) 
    { 
     case COMBINATION(0,0,0): function(); break; 
     case COMBINATION(0,0,1): error3(); break; 
     case COMBINATION(0,1,0): error2(); break; 
     case COMBINATION(0,1,1): error2(); break; 
     case COMBINATION(1,0,0): error1(); break; 
     case COMBINATION(1,0,1): error1(); break; 
     case COMBINATION(1,1,0): error1(); break; 
     case COMBINATION(1,1,1): error1(); break; 
    } 
}