なぜCで警告し、C ++でコンパイルできないのですか?
-
10-07-2019 - |
質問
このコードを使用する理由
int (*g)(int);
int (*h)(char);
h = g;
Cでは、コンパイル時に次のような警告を表示します:
「警告:互換性のないポインタ型からの割り当て」
C ++では、コンパイルできません。
解決
プロトタイプが一致しません。 g
は int
を取り、 int
を返す関数へのポインタです。 h
は char
を取り、 int
を返す関数。これらは2つの異なるタイプであるため、警告(リンゴをオレンジに割り当てる)です。
他のヒント
入力パラメーターが異なるため、2つの関数ポインターは同じシグネチャを持ちません。
関数ポインターは両方とも int を返し、 g は入力として int を受け入れ、 h は受け入れます入力パラメータとして char 。
int と char を混在させることもできますが、関数ポインターを混合しているため、コンパイラは何か間違ったことをしている可能性があることを正しく警告します。
サンプルコード:
#include <stdio.h>
int gf(int n)
{
return printf("gf(%d)\n", n);
}
int hf(char c)
{
return printf("hf('%c')\n", c);
}
int main()
{
int (*g)(int) = gf; // pointer to gf
int (*h)(char) = hf; // pointer to hf
g = h; // warning: possibly incompatible functions
g(65); // cast 65 to char and call h
return 0;
}
コンパイル:
$ gcc-4.exe -Wall a.c
a.c: In function 'main':
a.c:18: warning: assignment from incompatible pointer type
プログラムの実行:
$ ./a.exe
hf('A')
ご覧のとおり、Cではうまく動作しますが、コンパイラーは適切な警告を出します。これをC ++コードとしてコンパイルしようとすると、コンパイラはポインタージャグリングを受け入れません。
$ g++-4.exe a.c
a.c: In function 'int main()':
a.c:18: error: invalid conversion from 'int (*)(char)' to 'int (*)(int)'
1つは int
を受け入れる関数を指すように宣言され、もう1つは char
を受け入れる関数を指すように宣言されます。これらは異なる署名であるため、ポインターには互換性がありません。
gは、int型の1つの引数を取り、intを返す関数であり、hは、char型の1つの引数を取り、int型の結果を返す関数であると宣言しました。 2つの関数シグネチャは互換性がないため、一方のポインターから他方のポインターに割り当てることはできません。
gとhを関数として宣言しました。実際、私のコンパイラは「割り当ての左オペランドとして必要な左辺値」エラーを返しますが、このコードを警告だけでコンパイルできるのは奇妙に思えますか?
編集:元々、質問のコードはgとhを関数として宣言していました。現在、それらは関数ポインタに変更されており、実際に警告が表示されるだけです。
互換性のないポインタを割り当てているため。 1つの関数ポインターは引数として符号付き整数を取り、もう1つの文字(符号はシステムによって異なります)を取ります。どちらも同じ値を返しますが、まったく異なります。
警告を無視し、関数ポインタを使用して(キャストして実際にコンパイルします)、意味がわかります:)
関数のシグネチャが異なるため、これは正当なCまたは正当なC ++ではありません。問題は、コンパイラがそれを異なる方法で処理する理由です。どちらの標準にも、標準に違反するプログラムをどう処理するかに関する多くのガイダンスはありませんが、特定の違反には診断が必要です(そして、これらのケースは両方とも診断メッセージを提供します)。標準は通常、有効なCまたはC ++プログラムが何であるか、および与えられたときに実装が何をする必要があるかについて懸念しています。
CはC ++よりもかなり古い言語であり、Cコードの多くは、現在存在するものよりも厳密性の低いコンパイラーで記述されています。 C ++は最初から厳格であったため、先行標準C ++コードは特定の機能を使用しない有効な標準C ++コードになる傾向があります。
このため、CコンパイラはC ++コンパイラよりも寛容である可能性が高く、コンパイラが実際に使用するために作成されていることを前提としています。結局のところ、多くのCコードがこの作業のようなものを快く想定しており、その一部は非常に便利ですが、C ++でも同じではありません。
私が追加できるのは、Cでの関数マッチングがC ++とは異なるということです。 Cでは、名前のみを使用します(したがって、パラメーターのオーバーロードは実行できません)。 C ++では、各関数には異なる「署名」があり、パラメーターから構成されています。 (パラメーターのオーバーロードを実現する必要がありました。)。