9

我有一组已声明的函数,static并且fastcall. this它们中的大多数使用指向在 C++ 中或多或少扮演角色的结构的指针。有些函数在结构中不需要任何东西,但为了统一起见,我还是想将指针传递给它们。编译器会注意到没有使用该参数并忽略为其分配寄存器吗?

4

3 回答 3

9

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

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

如那里所写,函数调用编译为此:-

    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) 

它在哪里发送指针。

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

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

于 2013-01-12T08:50:54.417 回答
1

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

干杯,

安迪

于 2013-01-12T08:40:39.173 回答
0

您可以在函数定义中省略参数。这将向编译器提示未使用特定参数,它将利用它并优化代码

无效函数(结构演示 *){ ... }

于 2017-02-10T11:38:25.143 回答