c++ 表記 - 無名関数ポインタ変数に関数参照を割り当てることができるのはなぜですか?




function member (2)

これは、Zack Weinbergによって報告されたこのバグに関連している可能性が非常に高いです:

バグ68265 - 'int(*){}'のあとにサイレントに受け入れられる任意の構文的なナンセンス

なぜ、この無効なコードがg ++ 6.0で正常にコンパイルされるのですか? :)

C ++コンパイラは、以下のような不適切な構文を診断することができません。

  int main()
  {
      int (*) {}
         any amount of syntactic nonsense
         on multiple lines, with *punctuation* and ++operators++ even...
         will be silently discarded
         until the next close brace
  }

-pedantic -std = c ++ 98では、警告:拡張初期化子リストは-std = c ++ 11または-std = gnu ++ 11でのみ使用可能ですが、-std = c ++ 11では使用できません覗いて

トークン 'int(*){}'のいずれか1つ(またはそれ以上)が削除されると、エラーが発生します。 また、Cコンパイラにも同じバグはありません。

もちろん、 int (*) (int, int) {}や他のバリアントを試してみると、誤ってコンパイルされます。 興味深いのは、これと以前の重複/バグレポートとの違いは、 int (*) (int, int) = asdfasdfをスコープ内の名前にすることです。 しかし、GCCが宣言子IDを省略することを許しているという中核的な問題があるので、バグは本質的に異なっていることは間違いありません。

[n4567§7/ 8]: " init-declarator-listのinit-declaratorには、そのinit-declaratorによって宣言された名前であるdeclarator-idが 1つだけ含まれているため、宣言によって宣言された名前の1つになります。

ここには奇妙なことがあります:

int (*) (int, int) = main;

この特定のシナリオでは、GCCはmainのアドレスを取ることについて不平を言いません(配列のように&main&mainと等価です)。

次のコードはうまくコンパイルされていますが、私はなぜそれがわかりません。 誰かがなぜこれが合法であるか私に説明してもらえますか?

私はg ++(Debian 6.1.1-10)6.1.1 20160724を使ってコンパイルしています。

#include <iostream>

int sum(int x, int y) { return x + y; }

int main(int argc, char *argv[])
{
    using std::cout;

    int (*) (int, int) = &sum;
    cout << "what" << '\n';
}

補遺

次のプログラムは、g ++バージョン5.4.0を使用してうまくコンパイルしますが、gccでコンパイルできません。

int main()
{
    int (*) = 20;
}

まず第一に、標準ではそのようなことを保証するものは何もありません(割り当てられていないポインタをfreeすることは未定義の動作です)。

とにかく、 freeで渡すことはただそのメモリにアクセスしようとすることへの単なるねじれた道です。 もしポインタが指すメモリがWindows上で読み書き可能かどうかをチェックしたいのなら、本当に試してSEH例外を処理する準備をしておくべきです。 これは、実際にはIsBadxxxPtr関数が行うことであり、そのような例外を戻りコードに変換することによって行われます。

しかし、これはこのRaymond Chenの投稿で説明されているように、微妙なバグを隠すアプローチです。 つまり、長い話を簡単に言えば、ポインタが有効なものを指しているかどうかを判断する安全な方法はありません。そのようなテストをどこかで行う必要がある場合、そのコードに設計上の欠陥があると思います。





c++ language-lawyer