6

戻り型を除いて同一の関数型に関数をキャストできないのはなぜですか?、関数の型と関数のシグネチャの違いをより完全に理解したいと思います。

たとえば、関数のは通常、関数ポインタを処理するときに考慮する必要があり、関数の型にはその関数の戻り型が含まれます。

ただし、上記の質問に対するMike Seymourの回答に記載されているように、関数のシグネチャは関数のタイプとは異なります。シグニチャは、潜在的なオーバーロードされた関数の中から明確にするために確かに使用されます(関数の戻りタイプは一意の関数を識別する役割を果たさないことに注意してください)。しかし、ここで、関数のシグネチャと関数の型の関連性と重要性を理解したいと思います。C ++の関数シグネチャの唯一の目的は、過負荷の解決中に、過負荷の候補や過負荷セット内の一意の関数を識別することであると私は思います。

私は正しいですか?過負荷解決はC++の関数シグネチャの唯一の目的ですか?または、過負荷の解決以外に(または間接的にのみ関連する)関数シグネチャのその他の使用/アプリケーションはありますか?

補遺明確にするために、私は特に関数シグネチャの目的と関数の違いを理解しようとしていることに注意してください。つまり、関数ポインターの使用と、コンパイラー/リンカーによる呼び出し規約の実装の両方に関数型が必要であることを私は知っています。ただし、呼び出し規約は、過負荷の解決が完了した後にのみ関係します。私はここで、具体的には、(タイプではなく)関数シグネチャの唯一の目的が過負荷の解決であるかどうかを尋ねています。

4

2 に答える 2

2

標準では、名前のマングリングとリンクに署名が使用されると記載されています。

そうは言っても、名前マングリングは標準化されていません。リターンタイプは関数シンボルでは冗長です(有効なプログラムでは、指定された名前と引数を持つ関数に対して可能なリターンタイプは1つしかないため、2つの異なるシンボルを区別する必要はありません)が、それでも一部のABIには含まれていますおそらく上記の規則に違反していないことを再確認する方法として、マングルされた名前の関数の戻り型。

于 2012-12-03T16:42:39.417 に答える
2

私は正しいですか?

私に関する限り、他の目的もあります。Cにも関数シグネチャがありますが、オーバーロードはありません。

オーバーロードとは別に、関数シグニチャの基本的な目的は、特定のプラットフォームの呼び出し規約に準拠することです。

関数が引数を受け入れて値を返す場合、コンパイラは引数を関数に正しく渡すために、引数のタイプとサイズを知る必要があります。一般に、関数の引数はスタックにプッシュされます(ただし、これは、特に64ビットアーキテクチャシステムでは、普遍的なルールではありません)。次の状況を考えてみましょう。次のような関数を呼び出す場合

foo(42);

コンパイラは、関数に渡さなければならない整数値のサイズをどのようにして知るのでしょうか。数値42は、さまざまなビット幅を使用して表すことができます。たとえば、1、2、4(または8)バイトの整数として表すことができます。

00101010
0000000000101010
00000000000000000000000000101010

charたとえば、引数が(1バイト)、short(2バイト)、または4バイト(4バイト)であることを示す署名が関数にない場合int、コンパイラは次のようになります。正しいサイズを決定する方法はありません。これは、任意のバイト数をスタックにプッシュするが、関数が別のサイズを予期している場合、スタックの破損が発生することを意味します。

もう1つの良い例は、構造体を返すことです(struct)。通常、プリミティブ戻り値(整数や浮動小数点数など)はレジスターに返されます。これは通常、EAXx86のレジスタです。しかし、構造体を返す関数を作成したい場合はどうでしょうか。構造体の全体的なサイズが大きすぎてレジスターに収まらない場合、コンパイラーは、レジスターに割り当てるのではなく、戻り値をスタックにプッシュするコードを生成する必要があります。したがって、関数が次のように定義されている場合

int foo()
{
    return 1337;
}

またはとして

struct bar {
    int a;
    char b[16];
    float x;
};

struct bar foo()
{
    struct bar ret;
    ret.a = 0;
    memcpy(&ret.b, "abcdefghijklmno", sizeof(ret.b));
    ret.x = 3.1415927;
    return ret;
}

異なるアセンブリ(およびマシンコード)が生成されます。整数を返す最初の関数はEAX戻り値を格納するためにレジスタを使用しますが、2番目の呼び出しはスタックを使用する必要があります。

于 2012-12-03T16:44:59.060 に答える