Saya memiliki sekelompok fungsi yang semuanya dideklarasikan static
dan fastcall
. Kebanyakan dari mereka menggunakan pointer ke struct yang kurang lebih berperan sebagai this
di C++. Beberapa fungsi tidak memerlukan apa pun di struct, tetapi demi keseragaman saya tetap ingin meneruskan pointernya. Akankah kompiler memperhatikan bahwa argumen tersebut tidak digunakan dan mengabaikan pengalokasian register ke argumen tersebut?
Akankah kompiler mengoptimalkan argumen fungsi statis yang tidak digunakan?
Jawaban (3)
Saya menulis program omong kosong ini untuk mengujinya. Ada beberapa kode yang tidak masuk akal dalam fungsinya, dan memanggilnya beberapa kali karena jika tidak, kompiler hanya akan memasukkan seluruh pemanggilan fungsi sehingga membuat pengujian tidak berguna. (Saya tahu ini adalah campuran aneh antara C dan C++.... kode bodoh, tetapi masih berfungsi untuk menunjukkan masalahnya)
#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);
}
Seperti yang tertulis di sana, fungsi memanggil kompilasi ke ini :-
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)
Yang menunjukkan bahwa compiler memang akan menghilangkan parameter jika tidak digunakan. Namun jika saya menghapus komentar pada dua baris di sana untuk mengambil alamat fungsi tersebut maka segalanya berubah, malah menghasilkan ini :-
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)
Di mana ia TIDAK mengirim penunjuk.
Asumsi saya adalah bahwa dalam kasus pertama kompiler dapat membuktikan bahwa jika ia menghasilkan konvensi pemanggilan khusus ke fungsi tersebut maka tidak mungkin ada efek yang terlihat oleh pengguna tetapi dalam kasus kedua di mana Anda mengambil pointer ke fungsi tersebut, fungsinya dapat dipanggil dari modul lain yang dikompilasi secara terpisah yang tidak memiliki cara untuk mengetahui apakah parameter tersebut diperlukan atau tidak. Meskipun dalam hal ini tidak masalah apakah registernya disetel atau tidak, secara umum kompiler harus tetap berpegang pada pola pemanggilan yang tepat jadi saya berasumsi bahwa itu menghasilkan kode yang paling umum dan tidak akan menggunakan konvensi pemanggilan khusus jika bisa. Tidak membuktikan bahwa ia dapat melihat semua kode yang dapat memanggil fungsi tersebut.
Bagaimanapun, untuk menjawab pertanyaan itu, tidak, kompiler tidak akan selalu meneruskan parameter yang tidak digunakan dalam register tetapi saya pasti tidak akan menulis kode apa pun yang bergantung pada perilaku spesifik apa pun di sini seperti mengubah kode yang tidak terkait di tempat lain (mengambil alamat fungsi), diubah perilaku itu dan tidak ada yang dijamin oleh standar apa pun yang saya lihat.
Pertama-tama, kompiler harus memperingatkan Anda tentang argumen fungsi yang tidak digunakan, jika Anda menggunakan flag kompiler yang tepat (-Wall, misalnya). Saya sarankan untuk meninggalkan argumen yang tidak Anda gunakan di luar daftar argumen, meskipun saya' kurasa mereka akan dioptimalkan. Apa yang dapat Anda lakukan untuk memastikannya adalah mengkompilasi kode Anda dua kali, sekali dengan argumen dan sekali tanpa argumen, dan lakukan diff
di antara biner dan lihat apakah keduanya cocok. Saya pikir itu harus bergantung pada kompiler yang Anda gunakan, dan tanda optimasi.
Bersulang,
andi
diff
- seseorang tidak akan dapat memeriksa perbedaannya (karena eksekusi bergantung pada banyak hal lain yang mungkin berbeda untuk setiap proses eksekusi, terlebih lagi inisialisasi variabel tidak akan memakan banyak waktu
- person exexzian; 12.01.2013
do a diff between the binaries
- Saya menanyakan biner b/w yang berbeda dari apa? waktu eksekusi atau ??
- person exexzian; 12.01.2013
Anda dapat menghilangkan argumen dalam definisi fungsi. Ini akan memberikan petunjuk kepada kompiler bahwa argumen tertentu tidak digunakan, Ini akan memanfaatkannya dan mengoptimalkan kode
fungsi kosong(demo struktur *) { ... }