Рассмотрим следующий код:Вызов функции указатель которого назначенная функция имеет меньше аргументов, то тип указателя
#include <iostream>
typedef int (*test_func_t) (int, int, int);
int print_integer (int a)
{
std::cout << "num: " << a << "\n";
return a;
}
int main (int argc, char * argv[])
{
test_func_t func = (test_func_t) &print_integer;
std::cout << "calling with 3 parameters func(5,7,9)\n";
func(5,7,9);
return 0;
}
Как вы можете видеть, тип (test_func_t) определяется как функция с 3 ИНТ аргументами. Указателю функции (func) присваивается указатель на «print_integer», который получает только один аргумент, а затем указатель функции вызывается с тремя аргументами (5, 7, 9).
Этот код работает и производит выход «num: 5».
GDB disas выход (синтаксис Intel)
disas main
...
0x080486cb <+9>: mov DWORD PTR [esp+0x1c],0x804867d
...
0x080486e0 <+37>: mov DWORD PTR [esp+0x8],0x9
0x080486e8 <+45>: mov DWORD PTR [esp+0x4],0x7
0x080486f0 <+53>: mov DWORD PTR [esp],0x5
0x080486f7 <+60>: mov eax,DWORD PTR [esp+0x1c]
0x080486fb <+64>: call eax
disas print_integer
...
0x08048683 <+6>: mov DWORD PTR [esp+0x4],0x8048830
0x0804868b <+14>: mov DWORD PTR [esp],0x8049ae0
0x08048692 <+21>: call 0x8048530 <std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)@plt>
0x08048697 <+26>: mov edx,DWORD PTR [ebp+0x8]
0x0804869a <+29>: mov DWORD PTR [esp+0x4],edx
0x0804869e <+33>: mov DWORD PTR [esp],eax
0x080486a1 <+36>: call 0x80484d0 <std::ostream::operator<<(int)@plt>
Как вы можете видеть, остальные аргументы ([EBP + 0x12] и [EBP + 0x16]) просто не используется.
Мои вопросы:
- Это, кажется, работает на Linux x86 с __cdecl соглашение о вызове. Безопасно ли это для других архитектур и вызывать соглашения?
- Предоставляет ли какой-либо стандарт C/C++/определяет результат назначения указателя функции из функции, которая ожидает меньше аргументов?
Пример такого использования: Node.js-х NODE_MODULE регистрирует функцию, type имеет 3 аргументы [экспорта, модуль, Priv]. Это called with those 3, но формальные примеры показывают регистрацию функции с аргументами 1 или 2.
Нет и нет. Это неопределенное поведение. И это нигде не безопасно. –
Это не совсем определенно и, в общем, плохая идея и небезопасна. Хотя, с учетом сказанного, это была довольно распространенная практика, и в соответствии с соглашениями о вызовах, где она работает, она работает нормально. –
@EugeneSh. «Небезопасно» - я полностью согласен с этим. Есть ли пример, который заставляет этот тип вызова «ломать» вещи? (помимо явно неправильного использования и злоупотребления) –