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)  

これは、使用されていない場合、コンパイラーが実際にパラメーターを省略していることを示しています。 ただし、関数のアドレスを取得するために2行のコメントを外すと、状況が変わり、代わりに次のように生成されます:-

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) 

ポインタを送信する場所。

私の仮定では、最初のケースでは、コンパイラーは、関数へのカスタム呼び出し規約を生成した場合、ユーザーに表示される効果はあり得ないことを証明できますが、2番目のケースでは、関数へのポインターを取得します。パラメータが必要かどうかを知る方法がない別の個別にコンパイルされたモジュールから呼び出すことができます。この場合、レジスタが設定されているかどうかは関係ありませんが、一般にコンパイラは正確な呼び出しパターンに固執する必要があるため、最も一般的なコードを生成し、可能な場合はカスタム呼び出し規約を使用しないと思います関数を呼び出すことができるすべてのコードを表示できることを証明しません。

とにかく、質問に答えるために、コンパイラが常に未使用のパラメータをレジスタに渡すとは限りませんが、他の場所で無関係のコードを変更する(関数のアドレスを取得する)など、特定の動作に依存するコードをここに書き込むことはありません。その振る舞いであり、私が見ることができる標準によって保証されるものは何もありません。

于 2013-01-12T08:50:54.417 に答える
1

まず、適切なコンパイラフラグ(たとえば、-Wall)を使用すると、コンパイラは未使用の関数引数について警告する必要があります。使用しない引数は、引数リストから除外することをお勧めします。 dそれらは最適化されると思います。ただし、確実にするためにできることは、コードを2回コンパイルすることです。1回は引数あり、もう1回は引数なしでdiff、バイナリ間で実行し、それらが一致するかどうかを確認します。使用するコンパイラと最適化フラグに依存するはずだと思います。

乾杯、

アンディ

于 2013-01-12T08:40:39.173 に答える
0

関数定義では引数を省略できます。これにより、特定の引数が使用されていないというヒントがコンパイラに与えられます。これを利用して、コードを最適化します。

void func(struct demo *){...}

于 2017-02-10T11:38:25.143 に答える