web-dev-qa-db-ja.com

`((void(*)())0x1000)();`はどういう意味ですか?

これは、アドレス0x1000にジャンプするようにプログラムカウンタを設定することを目的としたコードです。私はそれが何をするのか知っていますが、その方法がわかりません。それは私のC言語の知識の欠如に関連しています。あなたは私を啓発することができるかもしれません。これがステートメント/関数です(私もそれが何であるかわかりません:))

((void (*)())0x1000)();

voidを返し、引数を受け入れない関数へのポインタだと思います。私が間違っている場合は私を訂正してください。

38

C宣言は、単純なルールを使用して裏返しにデコードされます。識別子から開始し、右側で[](配列)または()(関数)を確認してから、左側で確認します。括弧を交差させずに、値のタイプ(配列に格納されるか、関数によって返される)の側。括弧から脱出し、繰り返します。

例えば:

void (*p)()

p is(右側には何もありません)ポインタ(左側では、括弧を交差させないでください)to(括弧をエスケープし、次を読みますlevel)関数(右)何も返さない(左)。

識別子(この場合はp)が欠落している場合、残っているのは型宣言だけです。

括弧で囲まれ、値の前に置かれる型は型キャストです。

(void (*)())0x1000

数値0x1000何も返さない関数へのポインターに変換します(上記のpの宣言に関する段落の括弧の外側を参照してください)。

次のレベルでは、上記の式(関数へのポインターは関数名と同じ方法で使用できます)を使用して、ポイントされたコードを実行します。

分解された式全体を以下に示します。

(
  (
    void (*)()   /* type: pointer to function that doesn't return anything     */
  )0x1000        /* value 0x1000 treated as a value of the type declared above */
)                /* enclose in parentheses to specify the order of evaluation  */ 
();              /* the pointer above used as a function name to run the code  */
44
axiac

(void (*)())は、voidを返し、指定されていないが固定された数の引数を取る関数へのポインターです。

(void (*)())0x1000キャスト上記のタイプのリテラル0x1000です。

最後に、接尾辞()callsその関数。その前の式は角かっこで囲む必要があります。そうでない場合、接尾辞()は構文的に有効ではない0x1000にバインドされます。

キャストが実際に有効かどうかを確認するのはあなた次第です。そうでない場合、プログラムの動作はndefinedです。

17
Bathsheba

定数

_0x1000
_

タイプにキャストされます:

_(type)0x1000
_

タイプはvoid (*)() —パラメーターを受け取らない(右側の空の括弧)(おっと、 pmgによるコメント を参照)そして値を返さない関数へのポインター(アスタリスク) (左側のvoid)。アスタリスクの追加の親は、それをvoidに関連付けることを防ぎます。これにより、ここに_void *_タイプが誤って作成されます。

したがって、キャスト後、アドレス0x1000にパラメーターのないvoid関数へのポインターがあります。

_(void (*)())0x1000
_

そしてその機能...

_((void (*)())0x1000)
_

空のパラメータリストを追加することで呼び出されます。

_((void (*)())0x1000)();
_
13
CiaPan

そのコードを書いた人は、次のように読みやすい方法でコードを書き直すべきでした。

#define ADDRESS_OF_FUNCTION_X 0x1000

typedef void (*func_ptr_t)(void);

...

func_ptr_t function_x = (func_ptr_t)ADDRESS_OF_FUNCTION_X;
function_x();

コードが行うことは、今ではほとんど自己文書化されています。

6
Lundin