0
typedef void(*FUNC)(void);
int main(void)
{
        //intptr_t m;
    const static unsigned char insn[4] = { 0xff, 0xff, 0xff, 0xff };
        FUNC function = (FUNC) insn;
        function();
}

上記のコードは、Illegal instruction として出力します。誰かが理由を説明できますか? . 関数ポインターが関数のアドレスを持っていないためですか(配列のアドレスを持っているため、アドレスにジャンプできませんでした)

4

2 に答える 2

1

配列の最初の要素へのポインターは関数へのポインターではないため、変数を介して「関数」を呼び出すことにより、未定義の動作を呼び出しますfunction。未定義の動作を呼び出すと、何が起こる可能性があります。不正な命令によるクラッシュは完全に正当なものです。ディスクからすべてのデータを消去することも同様です。

基準に従って「期待」できるものは何もありません。コメントで示唆されているように、起こりそうなことは、配列のスタックに格納されたバイト(およびスタックの残りの部分で、引数リストや環境変数などinsnのスタック フレーム) が処理されることです。main()マシンコードとして。幸いなことに、バイトの 1 つが無効な (または不正な) 命令であり、プログラムが停止します。

于 2013-09-11T03:12:18.540 に答える
0

C11 J.5.7 関数ポインタのキャスト

1 オブジェクトへのポインタまたはへvoidのポインタは、関数へのポインタにキャストすることができ、データを関数として呼び出すことができます (6.5.4)。

2 関数へのポインターは、オブジェクトへのポインターまたはへのポインターにキャストできますvoid。これにより、関数を検査または変更することができます (たとえば、デバッガーによって) (6.5.4)。

配列名を関数ポインターにキャストするだけなら問題ありませんが、実際には関数ではないため、それを呼び出すのは未定義の動作です。

実際の関数ポインターのアドレスを配列に格納してから、それを関数ポインターにキャストして呼び出すことができます。ただし、unsigned char小さすぎるため、まだ機能しませんuintptr_t。代わりに使用してください。

于 2013-09-11T03:28:30.840 に答える