`int (*)(float)` が `int foo()` を指すと警告がトリガーされるのに、`int (*)(double)` がそれを指すと警告がトリガーされないのはなぜですか? 質問する

`int (*)(float)` が `int foo()` を指すと警告がトリガーされるのに、`int (*)(double)` がそれを指すと警告がトリガーされないのはなぜですか? 質問する

次のようなコードがあります:

int foo() { return 0; }
int main()
{
    int (*float_function)(float) = foo;
}

x86-64 GCC 12.2を とともに使用してコンパイルすると-Wall、警告 (リンク):

警告: 互換性のないポインター型 'int (*)()' からの 'int (*)(float)' の初期化 [-Wincompatible-pointer-types]

しかし、floatからdoubleリンク):

int foo(){ return 0;}
int main()
{
    int (*double_function)(double) = foo;
}

警告は消えました。

しかし、私はこれら両方に警告を与えるべきだと思います。

どこか間違っているのでしょうか? GCC が 2 番目の例についてエラーを出さないのはなぜでしょうか?

ベストアンサー1

int foo()は、パラメータを指定せずに宣言されています。これは、任意の引数を指定して呼び出すことができる廃止予定の機能です。関数を呼び出すと、整数引数はint(必要な場合) に昇格され、float引数は に昇格されますdouble

このため、この関数はfloatパラメータを受け取ることができず、 とは互換性がありますint (*)(float)が、 とは互換性がありますint (*)(double)

パラメータを取らない関数が必要な場合は、 として宣言します。int foo(void)これにより、両方と互換性がなくなります。

があっても、 は関数定義なので、コンパイラはパラメータがないことを認識しているdoubleため、コードは有効な Cint foo() {...}ではないことに注意してください (標準リファレンスについては、以下の chux のコメントを参照してください)。ほとんどのコンパイラでは、まだこれを許可しています。

これを宣言に置き換えてint foo();定義を別の場所に置くと、上記は正しいものになります。その場合、関連する標準引用 (C17 6.7.6.3/15) は次のようになります。

2 つの関数型に互換性があるためには、[...] 一方の型にパラメータ型リストがあり、もう一方の型が関数定義の一部ではなく空の識別子リストを含む関数宣言子によって指定されている場合、[...] 各パラメータの型は、デフォルトの引数の昇格を適用した結果の型と互換性がある必要があります。

おすすめ記事