2015-05-04 12 views
45

Niektóre osoby nie są świadome, że są to possible to pass and return structs by value in C. Moje pytanie dotyczy kompilatora, który tworzy niepotrzebne kopie podczas zwracania struktur w C. Czy kompilatory C, takie jak GCC, używają optymalizacji Return value optimization(RVO), czy jest to tylko koncepcja C++? Wszystko, co czytałem o RVO i elizacji kopiowania, dotyczy C++.Optymalizacja wartości zwracanej i kopiowanie elementów w C

Rozważmy przykład. Aktualnie implementuję double-double data type w C (lub raczej float-float na początek, ponieważ uważam, że łatwe jest testowanie urządzenia). Rozważ następujący kod.

typedef struct { 
    float hi; 
    float lo; 
} doublefloat; 

doublefloat quick_two_sum(float a, float b) { 
    float s = a + b; 
    float e = b - (s - a); 
    return (doublefloat){s, e}; 
} 

Czy kompilator zrobić tymczasową kopię wartości doublefloat mogę zwrócić lub może być tymczasowa kopia pomijana?

Co z nazwaną optymalizacją wartości zwracanej (NRVO) w C? Mam kolejną funkcję

W tym przypadku zwracam nazwaną strukturę. Czy można w tym przypadku usunąć kopię tymczasową?

Należy stwierdzić, że jest to ogólne pytanie dla C i że przykłady kodu, które tutaj wykorzystałem, są jedynie przykładami (kiedy to zoptymalizuję, będę używał SIMD z wewnętrznymi taktykami). Jestem świadomy, że mogłem spojrzeć na wynik montażu, aby zobaczyć, co robi kompilator, ale myślę, że jest to jednak interesujące pytanie.

+3

@BaummitAugen, nie byłem pewien, czy powinienem użyć znacznika C++. Ale wydaje mi się, że w moim pytaniu było jasne, że chodzi o C. Miałem nadzieję, że tag C++ przyciągnie ludzi, którzy są ekspertami w obu językach. –

+0

@BaummitAugen jest takie pojęcie w C w ogóle. Usunąłem tag 'C', ponieważ wydaje mi się to erudystyczne. –

+0

@IvayloStrandjev nadal pytanie dotyczy C, tag odnosi się do pytania, nie? – BeyelerStudios

Odpowiedz

35

RVO/NRVO są wyraźnie dozwolone zgodnie z zasadą „co-jeśli” w C.

W C++ można uzyskać dostrzegalnych skutków ubocznych, ponieważ już przeciążony konstruktor, destruktor, i/lub operator przypisania do daj te efekty uboczne (np. wydrukuj coś, gdy nastąpi jedna z tych operacji), ale w C nie masz możliwości przeciążenia tych operatorów, a wbudowane nie mają zauważalnych efektów ubocznych.

Bez ich przeciążania nie można dostrzec żadnych efektów ubocznych związanych z kopiowaniem, a zatem nie ma potrzeby zatrzymywania kompilatora.

+4

Adres zmiennej w funkcji i adres zmiennej przypisanej do zewnętrznej, mogą być identyczne, ponieważ mają niepokrywające się czasy życia: most tymczasowy nie może mieć podanego adresu, a współdzielenie adresu dwóch pozostałych zmiennych nie może być wykryte. To, jak sądzę, uniemożliwia wykrycie, że to się stało (teoretycznie) pod normą: w praktyce, jeśli zmienna w funkcji i zmienna przypisana do zewnętrznej mają ten sam adres, szanse na to, że jesteś świadkiem NRVO. – Yakk

+1

Testowanie tego na gcc, g ++, clang, clang ++, okazuje się, że wszyscy dobrze wykonują NRVO z wyjątkiem gcc '-xc', który generuje zbędne kopie, gdy masz:' struct s f() {struct s x = g(); return x; } ' – Peaker

31

Powodem, dla którego jest on objęty w C++, jest to, że w C++, RVO ma efekty uboczne (tj. Nie wywoływanie destruktora obiektów tymczasowych ani konstruktora kopiowania lub operatora przypisania obiektów wynikowych).

W języku C nie ma możliwych skutków ubocznych, a jedynie potencjalne ulepszenia wydajności. Nie widzę powodu, dla którego taka optymalizacja nie mogłaby zostać wykonana przez jakiś kompilator. Przynajmniej nie ma niczego, co zabraniałoby tego w standardzie.

W każdym razie, optymalizacja zależy od kompilatora i optymalizacji zależnych od poziomu, więc nie obstawiałbym go dla krytycznych ścieżek kodu, chyba że użyty kompilator jest dobrze zdefiniowany i nie oczekuje się zmiany (co jest nadal często takowe).

Powiązane problemy