编译器会优化静态函数的未使用参数吗?

我有一组函数都声明为staticfastcall 。 他们中的大多数都使用指向结构的指针,该结构在C ++中或多或少地扮演着this角色。 一些函数在结构中不需要任何东西,但为了统一起见,我还是要传递指针。 编译器是否会注意到该参数未被使用并且省略了为其分配寄存器?

我写了这个无意义的程序来测试这个。 它在函数中有一些无意义的代码,并多次调用它,因为否则编译器只是内联整个函数调用使测试无用。 (这是C和C ++的奇怪组合我知道……愚蠢的代码,但仍然可以certificate这个问题)

 #include  #include  #include  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 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); } 

在那里写的函数调用编译到这个: –

  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) 

这表明如果没有使用,编译器确实会省略参数但是,如果我取消注释那两行以获取函数的地址然后事情发生变化,它会生成这样的: –

 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) 

它发送指针的地方。

我的假设是,在第一种情况下,编译器能够certificate,如果它为函数生成了一个自定义调用约定,那么就不可能有任何用户可见效果,但在第二种情况下,你获取指向函数的指针,函数可以从另一个单独编译的模块调用,该模块无法知道参数是否需要。 虽然在这种情况下,无论寄存器是否设置都无关紧要,但一般情况下编译器需要坚持精确的调用模式,因此我假设它生成了最通用的代码,如果可以,则不会使用自定义调用约定不能certificate它可以看到所有可以调用该函数的代码。

无论如何,要回答这个问题,编译器不会总是在寄存器中传递未使用的参数,但我当然不会编写任何依赖于任何特定行为的代码,因为在其他地方更改不相关的代码(获取函数的地址),更改这种行为并没有任何我能看到的标准保证。

首先,编译器应该警告你有关未使用的函数参数,如果你使用正确的编译器标志(例如-Wall)。我建议保留你不使用参数列表的参数,尽管我我猜他们会被优化掉。 然而,您可以做些什么来确保编译代码两次,一次使用参数,一次不使用,并在二进制文件之间进行diff ,看看它们是否匹配。 我认为它应该取决于您使用的编译器和优化标志。

干杯,

安迪

您可以省略函数定义中的参数。 这将给编译器提示不使用相关参数,它将从中受益并优化代码

void func(struct demo *){…}