调用一个函数指针,其指定函数的参数少于指针类型

请考虑以下代码:

#include  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个int参数的函数。 函数指针(func)被赋予一个指向“print_integer”的指针,该指针只接收一个参数,然后用3个参数(5,7,9)调用函数指针。

此代码工作并生成“num:5”输出。

gdb disas输出(Intel语法)

 disas main ... 0x080486cb : mov DWORD PTR [esp+0x1c],0x804867d ... 0x080486e0 : mov DWORD PTR [esp+0x8],0x9 0x080486e8 : mov DWORD PTR [esp+0x4],0x7 0x080486f0 : mov DWORD PTR [esp],0x5 0x080486f7 : mov eax,DWORD PTR [esp+0x1c] 0x080486fb : call eax disas print_integer ... 0x08048683 : mov DWORD PTR [esp+0x4],0x8048830 0x0804868b : mov DWORD PTR [esp],0x8049ae0 0x08048692 : call 0x8048530 <std::basic_ostream<char, std::char_traits >& std::operator<< <std::char_traits >(std::basic_ostream<char, std::char_traits >&, char const*)@plt> 0x08048697 : mov edx,DWORD PTR [ebp+0x8] 0x0804869a : mov DWORD PTR [esp+0x4],edx 0x0804869e : mov DWORD PTR [esp],eax 0x080486a1 : call 0x80484d0 <std::ostream::operator< 

如您所见,其余参数([ebp + 0x12]和[ebp + 0x16])根本就没有使用过。

我的问题:

  1. 这似乎适用于具有__cdecl调用约定的Linux x86。 它在其他架构和调用约定上是否安全?
  2. 是否有任何C / C ++标准允许/定义从期望较少参数的函数中分配函数指针的结果?

此类用法示例:node.js的NODE_MODULE注册一个函数,其类型有3个参数[exports,module,priv]。 用这3个调用它,但是正式的例子显示了用1或2个参数注册函数。

引用C ++ 11标准expr.reinterpret.cast 6

函数指针可以显式转换为不同类型的函数指针。 通过指向函数类型(8.3.5)的函数调用函数的效果是未定义的 ,该函数类型与函数定义使用的类型不同

所以,我会说它一般不安全。 这是未定义的行为。 也就是说,我不知道在这种情况下C ++的其他实现如何表现。

因此,将适用于使用__cdecl调用约定的所有平台。 此调用约定将参数从右向左推送到堆栈,然后调用该函数。 因此,需要比推动的参数少的参数的函数将不会更多地访问右边的参数,这些参数被更早地推送并且在堆栈上更高。

 // func(5,7,9); push 9 push 7 push 5 call func ---> func: push bp mov bp, sp mov ax, [bp+8] ; get 5 // stack: 9 7 5 [bp+8]  [bp+4]  ^ new bp: -------------+