Mam grupę funkcji, które są zadeklarowane jako static
i fastcall
. Większość z nich wykorzystuje wskaźnik do struktury, która pełni mniej lub bardziej rolę w C++. Niektóre funkcje nie wymagają niczego w strukturze, ale w celu zachowania jednolitości chcę mimo wszystko przekazać im wskaźnik. Czy kompilator zauważy, że argument nie jest używany i nie przypisuje do niego rejestru?Czy kompilator zoptymalizuje nieużywane argumenty funkcji statycznej?
Odpowiedz
Napisałem ten program, aby przetestować ten nonsens. Ma w tym funkcję jakiś nonsensowny kod i wywołuje go kilka razy, ponieważ w przeciwnym razie kompilator po prostu wywołał całe wywołanie funkcji, czyniąc test bezużytecznym. (To dziwna mieszanka C i C++, wiem .... głupiego kodu, ale nadal działa w celu wykazania wystawienia)
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct demo
{
int a;
char ch;
};
static void __fastcall func(struct demo* d)
{
for(int i = 0; i < 100; i++) {
std::vector<int> a;
std::sort(begin(a), end(a));
printf("THis is a test");
printf("Hello world\n");
}
}
int main()
{
// void*p = (void*)&func;
struct demo d;
func(&d);
func(&d);
func(&d);
func(&d);
func(&d);
func(&d);
func(&d);
//printf((const char*)p);
}
Jak tam napisane wywołania funkcji kompilacji do tego: -
func(&d);
00F61096 call func (0F61000h)
func(&d);
00F6109B call func (0F61000h)
func(&d);
00F610A0 call func (0F61000h)
func(&d);
00F610A5 call func (0F61000h)
func(&d);
00F610AA call func (0F61000h)
func(&d);
00F610AF call func (0F61000h)
func(&d);
00F610B4 call func (0F61000h)
Co pokazuje, że kompilator rzeczywiście pominie parametr, jeśli nie jest używany. Jednak gdybym odkomentowaniu dwie linie tam wziąć adres funkcji następnie rzeczy zmienić, to zamiast generowane w ten sposób: -
00C71099 lea ecx,[esp]
00C7109C call func (0C71000h)
func(&d);
00C710A1 lea ecx,[esp]
00C710A4 call func (0C71000h)
func(&d);
00C710A9 lea ecx,[esp]
00C710AC call func (0C71000h)
func(&d);
00C710B1 lea ecx,[esp]
00C710B4 call func (0C71000h)
Gdzie robi wysłać wskaźnik.
Moje założenie jest takie, że w pierwszym przypadku kompilator jest w stanie dowieść, że jeśli wygenerował niestandardową konwencję wywołującą dla funkcji, która nie może być widocznymi dla użytkownika efektami, ale w drugim przypadku, gdy przyjmiemy wskaźnik do funkcja może być wywołana z innego, osobno skompilowanego modułu, który nie ma możliwości sprawdzenia, czy parametr jest potrzebny, czy nie. Chociaż w tym przypadku nie ma znaczenia, czy rejestr został ustawiony, czy nie, ogólnie kompilator musi trzymać się dokładnego wzorca wywołującego, więc zakładam, że wygenerował on najbardziej ogólny kod i nie użyje niestandardowych konwencji wywoływania, jeśli to możliwe. udowodnić, że widzi cały kod, który mógłby wywołać funkcję.
W każdym razie, aby odpowiedzieć na pytanie, nie kompilator nie będzie zawsze przekazywał nieużywanych parametrów w rejestrze, ale na pewno nie napisałbym kodu, który zależy od konkretnego zachowania tutaj, jak zmiana niepowiązanego kodu w innym miejscu (przyjmowanie adresu funkcja), zmieniło to zachowanie i nic nie gwarantuje żaden standard, jaki widzę.
Przede wszystkim kompilator powinien ostrzegać o nieużywanych argumentach funkcji, jeśli użyjesz odpowiednich flag kompilatora (na przykład: -Wall) .Przypisz by zostawić argumenty, których nie używasz z listy argumentów , chociaż sądzę, że zostaną zoptymalizowane. Co możesz zrobić, aby upewnić się, to jednak jest skompilowanie kodu dwa razy, raz z argumentami i raz bez, i zrobić diff
między binariami i sprawdzić, czy pasują. Myślę, że powinien on zależeć od używanego kompilatora i flag optymalizacyjnych.
Cheers,
Andy
zgodził się, że kompilator optymalizuje go, ale sprawdza go za pomocą 'diff' - jeden nie będzie w stanie sprawdzić różnic (ponieważ wykonanie zależy od wielu innych rzeczy, które mogą się różnić dla każdego procesu wykonywania, ponadto inicjalizacja zmiennych nie przyniesie tak wiele czas – exexzian
@sansix, jeśli pliki binarne są równe, dlaczego zachowanie ma się różnić? –
Przy okazji - diff b/w binaraies czego? (może myślę w inny sposób) – exexzian
Możesz pominąć argument w definicji funkcji. To daje wskazówkę do kompilator, że perticular argument nie jest używany, to zajmie korzyści z niego i optymalizować kod
void func (struct demo *) { ... }
- 1. Czy kompilator zoptymalizuje podział na mnożenie?
- 2. Czy kompilator .NET JIT zoptymalizuje wywołanie metody?
- 3. Nieużywane argumenty w R
- 4. Czy kompilator Swift ignoruje nieużywane funkcje?
- 5. Czy kompilator zoptymalizuje funkcje zwracające struktury z macierzami o ustalonych rozmiarach?
- 6. F # argumenty funkcji zmienny
- 7. Czy kompilator C# zoptymalizuje wywołania do tej samej metody w pętli?
- 8. W jaki sposób kompilator Scala obsługuje nieużywane wartości zmiennych?
- 9. Argumenty szablonów do funkcji szablonu
- 10. Czy można implodować tablicę na argumenty funkcji?
- 11. Czy umieściłem [[być może nieużywane]] w deklaracjach funkcji lub definicjach?
- 12. Inline Argumenty funkcji Uboczny
- 13. Argumenty funkcji wiele typów
- 14. Referencje jako argumenty funkcji?
- 15. Czy argumenty funkcji zestawu parametrów mogą być domyślne?
- 16. javascript opcjonalne argumenty funkcji
- 17. Jaka jest składnia funkcji statycznej?
- 18. niezdefiniowane odniesienie do funkcji statycznej
- 19. Jak ustawić kompilator statycznej wersji szablonu nad wskaźnikiem?
- 20. Rozwiń wektor na argumenty funkcji
- 21. Argumenty funkcji JavaScript dla funkcji filtru
- 22. Dostęp argumenty funkcji od dekoratora
- 23. Wyluzuj sześcienny - Argumenty funkcji Wyjaśnienie
- 24. Nieograniczone argumenty w funkcji JavaScript
- 25. Czy jest możliwe dodanie "statycznej" funkcji rozszerzenia dla klasy Java?
- 26. Czy budowa obiektu funkcji statycznej zakresu jest bezpieczna dla wątków?
- 27. Czy nienazwane argumenty są w programie Go?
- 28. Czy istnieje kompilator R?
- 29. Wyodrębnianie nazw funkcji z biblioteki statycznej
- 30. Zapobieganie importowaniu funkcji z biblioteki statycznej
ma sens, że podanie adresu funkcji nie pozwala na zoptymalizowanie nieużywanych parametrów, ponieważ wskaźnik funkcji jest wpisywany do podpisu funkcji (nawet jeśli rzutuje się go na void *), a kompilator nie może na ogół upewnij się, że użyjesz go ponownie przez jakąś dziwną magię. +1 za wskazanie tego problemu. –
Rzeczywiście. Zastanawiam się, czy z generowaniem kodu czasu połączenia kompilator może i tak korzystać z niestandardowej konwencji wywoływania, ponieważ może "zobaczyć" cały kod, ale najwyraźniej nie, przynajmniej w przypadku mojego testu. – jcoder
Głównym wnioskiem, który zabrałbym z mojego testu, nie jest ani jedno, ani drugie. Może, ale nie musi, przekazywać parametr do rejestru. – jcoder