Panggil fungsi dari alamatnya melalui fungsi templat

Dengan asumsi saya memiliki alamat memori runtime suatu fungsi dalam Aplikasi dan saya mengetahui tipe kembalian dari fungsi tersebut, apakah mungkin untuk memanggil fungsi tersebut, mengetahui tipe kembalian fungsi, argumennya dan konvensi pemanggilannya, menggunakan templat variadik?

Fungsi templat harus mendukung tipe pengembalian void dan non-void. Karena kenyataan bahwa kita berurusan dengan penunjuk fungsi, kompiler tidak boleh mengeluh, meskipun mengembalikan ptr.

Saya berpikir untuk melakukan sesuatu seperti ini:

template<typename ReturnType, typename Address, typename... Args>
ReturnType function_caller(Address address, Args... args)
{
    ReturnType(*ptr)(Args...) = address;
    return ptr(args...);
}
int main()
{
    auto address = 0x100;
    auto address2 = 0x200;
    function_caller<void>(&address, 1, 1); // Function with return type void.
    int result = function_caller<int>(&address2, 1, 2, 3.f, "hello"); 
    // result should contain the int value we received by calling the function at 0x200

}

Sayangnya kompiler memunculkan kesalahan C2440: Tidak dapat mengubah Alamat address menjadi 'ReturnType (__cdecl *)(int,int)'

Saya akan sangat menghargai bantuan Anda dalam masalah ini. Saya tahu saya bisa membagi pembungkus ini menjadi 2 fungsi: satu untuk panggilan batal dan satu lagi untuk panggilan non-void, tapi saya berharap ada solusi yang lebih elegan dan didukung template.

Terima kasih dan semoga harimu menyenangkan!


person Troganda    schedule 25.08.2020    source sumber
comment
Ya saya tahu, alamat tersebut bukanlah alamat sebenarnya dan hanya untuk menunjukkan konsepnya. Ini bukan kode yang akan saya gunakan saat runtime. Harap asumsikan saja alamatnya benar. Selain itu, kompiler tidak akan keberatan karena ini adalah kesalahan waktu proses, bukan waktu kompilasi   -  person Troganda    schedule 25.08.2020
comment
Pengurangan parameter secara otomatis juga berbahaya. Apakah parameter keempat itu const char* atau const char[6]? Saya cukup yakin itu yang terakhir.   -  person Mooing Duck    schedule 25.08.2020
comment
Jika Anda ingin memiliki sintaks aneh untuk panggilan batal, Anda juga dapat membujuknya untuk menyimpulkan tipe pengembalian. coliru.stacked-crooked.com/a/42c1c60bf0e2f50a   -  person Mooing Duck    schedule 25.08.2020


Jawaban (1)


jawabannya adalah ya, tapi melakukannya dengan template variadic berbahaya.

untuk menegakkan kompiler untuk memberikan alamat ke penunjuk fungsi, Anda perlu menggunakan reinterpret_cast atau c cast .

catatan: Anda salah memasukkan alamat integral ke sebuah penunjuk karena Anda sebenarnya mencoba memasukkan alamat variabel yang berisi alamat ke penunjuk, bukan alamat itu sendiri!

jadi baris ini:

function_caller<void>(&address, 1, 1); // Function with return type void.

seharusnya :

function_caller<void>(address, 1, 1); // Function with return type void.

dan selalu gunakan jenis alamat sebagai uintptr_t yang sesuai untuk alamat apa pun yang tersedia untuk arsitektur (64 bit atau 32)

tetapi melakukannya dengan templat variadik tidak aman sama sekali. alasannya adalah fungsi tersebut memiliki tipe argumen tertentu seperti ini:

int fn(std::string& str, const char* ptr, uint64_t& i);

tetapi ketika Anda menggunakan templat variadik, kompiler akan menyimpulkan tipe dari argumen yang diteruskan namun beberapa konversi mungkin diperlukan!

jadi dalam versi Anda saat ini:

int i;
function_caller<int>(0x15216516, "str", "ptr", i);

kompilasi akan berasumsi bahwa tanda tangan fungsi adalah seperti:

int fn(const char*, const char*, int); // wrong types means stack corruptions and undefined behaviors

lihat juga ini:

std::string to_string(std::string_view v);

function_caller<std::string>(0x15216516, "str"); // wrong the compiler won't convert the string literal for you and the function will end up with a dangling view

function_caller<std::string>(0x15216516, std::string("str")); // wrong again there is no conversion from std::string to std::string_view here

jadi ini benar-benar dapat diandalkan hanya untuk menentukan seluruh jenis fungsi dan menggunakannya untuk memberikan alamat seperti yang dilakukan boost.dll

person dev65    schedule 25.08.2020
comment
Tidak, kedua parameternya adalah const char[4], bukan const char* - person Mooing Duck; 25.08.2020