2014-12-09 6 views
6

Betrachten Sie das folgende hypothetische Typ: (. Rein für eine verbesserte Lesbarkeit)Werden Compiler doppelte logische Negation in Bedingungen optimieren?

typedef struct Stack { 
    unsigned long len; 
    void **elements; 
} Stack; 

Und die folgenden hypothetischen Makros für mit der Art zu tun in diesen Makros ich am davon aus, dass das gegebene Argument Typ hat (Stapel *) statt nur Stack (ich kann hier nicht einen _Generic Ausdruck tippen belästigt werden.)

#define stackNull(stack) (!stack->len) 
#define stackHasItems(stack) (stack->len) 

Warum einfach verwende ich nicht !stackNull(x) zum Prüfen, ob ein Stapel Artikel hat? Ich dachte, dass dies etwas weniger effizient wäre (lies: überhaupt nicht wahrnehmbar, aber ich fand es interessant), als einfach stack->len zu überprüfen, weil es zu einer doppelten Negation führen würde. Im folgenden Fall:

int thingy = !!31337; 
printf("%d\n", thingy); 
if (thingy) 
    doSomethingImportant(thingy); 

Die Zeichenfolge „1 \ n“ gedruckt werden würde, und es wäre unmöglich, die bedingten (na ja eigentlich nur unmöglich, wenn das Dingen Variable nicht über einen konstanten initializer zu optimieren oder wurde vor dem Test geändert, aber wir werden in diesem Fall sagen, dass 31337 keine Konstante ist), weil (!!x) garantiert entweder 0 oder 1 ist.

Aber ich frage mich, ob Compiler so etwas wie die folgenden

int thingy = wellOkaySoImNotAConstantThingyAnyMore(); 
if (!!thingy) 
    doSomethingFarLessImportant(); 

Wird diese optimiert werden, um tatsächlich nur (Dingen) verwendet in der if-Anweisung optimieren, als ob die if Aussage als

geschrieben worden war
if (thingy) 
    doSomethingFarLessImportant(); 

Wenn ja, erweitert es sich auf (!!!!!thingy) und so weiter? (Dies ist jedoch eine etwas andere Frage, da dies in jedem Fall optimiert werden, !thingy ist !!!!!thingy egal was, wie -(-(-(1))) = -1.)

In der Frage Titel I „Compiler“, sagte, damit meine ich, dass ich frage wenn jeder Compiler dies tut, aber ich bin besonders daran interessiert, wie GCC in diesem Fall verhalten wird, wie es mein Compiler der Wahl.

+3

Jeder Compiler, der * diese triviale Optimierung nicht gemacht hat, würde ich als inakzeptabel betrachten. –

Antwort

7

Dies scheint ein ziemlich reasonable optimization und einen schnellen Test mit godbolt mit diesem Code (see it live):

#include <stdio.h> 

void func(int x) 
{ 
    if(!!x) 
    { 
    printf("first\n") ; 
    } 

    if(!!!x) 
    { 
    printf("second\n") ; 
    } 
} 

int main() 
{ 
    int x = 0 ; 

    scanf("%d", &x) ; 
    func(x) ; 
} 

scheint gcc tut gut, um anzuzeigen, erzeugt er folgendes:

func: 
    testl %edi, %edi # x 
    jne .L4 #, 
    movl $.LC1, %edi #, 
    jmp puts # 
.L4: 
    movl $.LC0, %edi #, 
    jmp puts # 

wir von der ersten Zeile sehen:

testl %edi, %edi # x 

verwendet es nur x ohne Operationen tun Sie darauf Beachten Sie auch, dass der Optimierer clever genug ist, beide Tests zu einem zu kombinieren, denn wenn die erste Bedingung true ist, muss die andere false sein.

Hinweis Ich habe printf und scanf für Nebenwirkungen verwendet, um zu verhindern, dass der Optimierer den gesamten Code optimiert.

+2

In der Tat, sogar mit '-O' (Optimierungen ausgeschaltet), meine installierte Kopie von gcc-4.8.3 produziert identischen Code für '! X' und' !!! x'. – ArjunShankar

Verwandte Themen