私はこれを理解できません:
_int main() {
int (*) (int *) = 5;
return 0;
}
_
上記の割り当ては、g ++ c ++ 11でコンパイルされます。 int (*) (int *)
は、_(int *)
_を引数として受け取り、intを返す関数へのポインタであることは知っていますが、どのようにそれを5に等しくすることができるかわかりません。常に5を返す関数(F#での最近の学習から、おそらく笑)、次に、簡単に、関数ポインターがメモリ位置5を指していると思いましたが、それは明らかに動作せず、16進数値も動作しません。
関数がintを返すためである可能性があり、intを割り当てることは(なんとか)大丈夫だと考えて、私もこれを試しました:
_int * (*) (int *) = my_ptr
_
ここで_my_ptr
_は_int *
_型であり、この2番目の関数ポインターと同じ型で、int型の最初の場合と同じです。これはコンパイルされません。 _my_ptr
_の代わりに5または任意のint値を割り当てても、この関数ポインター用にコンパイルされません。
では、割り当てはどういう意味ですか?
更新1
ベストアンサーに示されているように、バグであることを確認しています。ただし、関数ポインターに割り当てる値に実際に何が起こるかがどうなるか、または割り当てで何が起こるかはまだわかりません。それについての(良い)説明は非常にありがたいです!問題の詳細については、以下の編集を参照してください。
編集1
Gccバージョン4.8.2を使用しています(Ubuntu 4.8.2で)
編集2
実際には、それをあらゆるものと同等にすることは、私のコンパイラーで機能します。 std :: string変数、またはdoubleを返す関数名と同等である場合でも機能します。
編集2.1
興味深いことに、ポインターではないデータ型を返す関数への関数ポインターにすると、次のようにコンパイルできます。
_std::string (*) () = 5.6;
_
しかし、関数ポインターがポインターを返す関数を指すとすぐに、次のようにコンパイルされません。
_some_data_type ** (*) () = any_value;
_
これはg ++のバグです。
int (*) (int *)
型名です。
C++では、識別子のない型名を持つ宣言を持つことはできません。
したがって、これはg ++でコンパイルされます。
int (*) (int *) = 5;
これもコンパイルします:
int (*) (int *);
しかし、両方とも無効な宣言です。
[〜#〜] edit [〜#〜]:
T.C。 コメントBugzillaのバグに言及 6068 同様のテストケース しかし、まだ承認されていません。バグはbugzillaで確認されています。
EDIT2:
上記の2つの宣言がファイルスコープにある場合、g ++は診断を正しく発行します(ブロックスコープで診断を発行できません)。
EDIT3:
G ++バージョン4(4.9.2)の最新リリース、最新のプレリリースバージョン5(5.0.1 20150412)、および最新の実験バージョン6(6.0.0 20150412)で問題を確認し、再現できます。
有効なC++ではありません。特定のコンパイラはたまたまコンパイルされるため、有効になりません。コンパイラは、すべての複雑なソフトウェアと同様に、バグがある場合があり、これはバグのようです。
対照的にclang++
文句:
funnycast.cpp:3:11: error: expected expression
int (*) (int *) = 5;
^
funnycast.cpp:3:18: error: expected '(' for function-style cast or type construction
int (*) (int *) = 5;
~~~ ^
funnycast.cpp:3:19: error: expected expression
int (*) (int *) = 5;
^
3 errors generated.
問題のある行が有効なC++ではないため、これは予想される動作です。それは割り当てであると主張しています(=
)が識別子を含みません。
他の回答が指摘しているように、それはバグです
int (*) (int *) = 5;
コンパイルします。意味を持つと予想されるこのステートメントの合理的な近似は次のとおりです。
int (*proc)(int*) = (int (*)(int*))(5);
proc
は、5
を取り、int
を返す関数のベースアドレスであるアドレスint*
を期待する関数へのポインターです。
一部のマイクロコントローラ/マイクロプロセッサでは、5
が有効なコードアドレスである場合があり、そのような関数をそこに配置できる場合があります。
ほとんどの汎用コンピューターでは、null
ポインターアクセスをキャッチするために、メモリの最初のページ(4Kページのアドレス0-1023
)は意図的に無効(マップされていない)です。
したがって、動作はプラットフォームに依存しますが、*proc
が呼び出されたときにページフォールトが発生すると合理的に予想できます(たとえば、(*proc)(&v)
)。 *proc
が呼び出される前に、異常なことは何も起こりません。
動的リンカーを作成しているのでなければ、アドレスを数値的に計算して、それらを関数へのポインター変数に割り当てるべきではありません。
/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/cc1plus.exe -da so.cpp
このコマンドラインは、多くの中間ファイルを生成します。最初のso.cpp.170r.expand
、言う:
...
int main() ()
{
int D.2229;
int _1;
;; basic block 2, loop depth 0
;; pred: ENTRY
_1 = 0;
;; succ: 3
;; basic block 3, loop depth 0
;; pred: 2
<L0>:
return _1;
;; succ: EXIT
}
...
これはまだ正確に何が起こるかには答えませんが、正しい方向への一歩であるべきです。