2017-12-07 81 views
5

6.5.2.5p5 mówiTrwałość związku dosłownym

Jeśli związek dosłownym zachodzi poza organizmem funkcji, celem ma statyczny czas przechowywania; w przeciwnym razie ma on automatyczny czas przechowywania związany z blokiem obejmującym .

Czy słusznie interpretuję tutaj "otaczający blok" jako "najgłębszy blok otaczający"? (Bo jeśli nie jest to najgłębsza jeden, co to jest?) Why are gcc and clang behaving as if the lifetime of a literal were its enclosing function?

Przykład:

long foo(long*); 

void call_foo() 
{ 
    {foo(&(long){42});} 
    {foo(&(long){42});} 
    {foo(&(long){42});} 
    {foo(&(long){42});} 
} 

//for comparison 

void call_foo2() 
{ 
    {long x=42;foo(&x);} 
    {long x=42;foo(&x);} 
    {long x=42;foo(&x);} 
    {long x=42;foo(&x);} 
} 

kod generowany przez gcc/brzękiem na -O3:

call_foo: 
    sub rsp, 40 
    mov rdi, rsp 
    mov QWORD PTR [rsp], 42 
    call foo 
    lea rdi, [rsp+8] 
    mov QWORD PTR [rsp+8], 42 
    call foo 
    lea rdi, [rsp+16] 
    mov QWORD PTR [rsp+16], 42 
    call foo 
    lea rdi, [rsp+24] 
    mov QWORD PTR [rsp+24], 42 
    call foo 
    add rsp, 40 
    ret 
call_foo2: 
    sub rsp, 24 
    lea rdi, [rsp+8] 
    mov QWORD PTR [rsp+8], 42 
    call foo 
    lea rdi, [rsp+8] 
    mov QWORD PTR [rsp+8], 42 
    call foo 
    lea rdi, [rsp+8] 
    mov QWORD PTR [rsp+8], 42 
    call foo 
    lea rdi, [rsp+8] 
    mov QWORD PTR [rsp+8], 42 
    call foo 
    add rsp, 24 
    ret 
+4

Czy mógłbyś rozwinąć swoje myśli na temat kodu, który wyświetlasz? Jak myślisz, co jest z tym problematyczne? Dlaczego to jest problem? I pytasz tylko z powodu ciekawości, czy jest jakiś inny powód, o który pytasz? Jaki jest * rzeczywisty * problem, który doprowadził do tego postu? –

+1

@Someprogrammerdude Ten złożony kod dosłowny (którego chcę użyć, bo go lubię) jest pozornie niepotrzebnie marnuje moje cenne miejsce na stos na nie 1, ale 2 głównych kompilatorach optymalizacyjnych, co mi przeszkadza, więc chcę wiedzieć, czy istnieje powód dla tego. – PSkocik

+1

Litery złożone zachowują się tak, jak każdą inną zmienną - ich zakres jest ograniczony do bloku '{}, w którym są zadeklarowane. Lub jeśli poza funkcją, mają zasięg pliku i czas przechowywania statycznego - tak jak każda inna zmienna. Co do tego, dlaczego dostajesz ten kod maszynowy, nie wiem. Wydaje się dziwne. Spodziewam się, że ponownie użyje tego samego obszaru stosu. – Lundin

Odpowiedz

5

Nie wydaje być tego dobrym powodem. Nazwałbym to błędem kompilatora.

0

Rozważmy kod:

void whatever(void) 
{ 
    THING *p; 
    ... 
    if (condition1) 
     p=&(THING){...whatever...}; 
    ... 
    doSomethingWith(p); 
} 

Sposób standard jest napisane, związek dosłownego będzie użyteczny tylko wtedy, gdy przypisanie do p wykonywana jest przez samotnego non-związek rachunku kontrolowanego przez if; zmianę kodu więc if kontrolowane oświadczenie związek wymagałoby znaczącego przeróbek:

void whatever(void) 
{ 
    THING *p,temp_thing; 
    ... 
    if (condition1) 
    { 
     temp_thing = (THING){...whatever...}; 
     // Or else temp_thing.field1 = value1; temp_thing.field2=value2; etc. 
     p=&temp_thing; 
    } 
    ... 
    doSomethingWith(p); 
} 

Taki wymóg znacznie i niepotrzebnie osłabić przydatność literałów złożonych (ponieważ kod może być napisane na temat, jak również bez nich). O wiele bardziej rozsądna zasada wskazywałaby, że okres istnienia literału złożonego rozciąga się, dopóki kod nie opuści funkcji, w której został użyty, lub wyrażenie, które go tworzy, zostanie ponownie wykonane, w zależności od tego, co nastąpi wcześniej. Ponieważ Standard zezwala kompilatorom na wydłużenie czasu życia obiektów automatycznych, ale uważają to za stosowne, fakt, że robi to kompilator, nie powinien być uważany za błąd. Z drugiej strony, kompilator jakości, który celowo będzie bardziej przydatny niż wymaga Standard, powinien prawdopodobnie wyraźnie udokumentować ten fakt. W przeciwnym razie przyszli opiekunowie mogą zadeklarować, że wszelkie programy, które polegają na takim rozsądnym zachowaniu, są "wadliwe" i że kompilator może być bardziej "wydajny", jeśli przestanie je wspierać.