1

私はエレクトロニクスの男ですので、よろしくお願いします。

8 ビット マイクロコントローラのリアルタイム オペレーティング システムに関するこの記事を読んでいました。私は奇妙な見た目の引数でこの関数に出くわしました。私はそれが何をしているのか理解できませんでした。私はそれがvoid「タイプなし」を意味することを知っています。(*Task)それがキャスティングだと思います。その後、これらの括弧が何をするのか本当にわかりません。

この関数の引数には何が含まれますか?

また、私は何をするのか理解できませんでした*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;か?

ここに画像の説明を入力

4

3 に答える 3

7

void (*Task)()実際には関数ポインタです。基本的には次のように言っています。「パラメータ名はTaskであり、これは戻り値を返す関数でありvoid、(これはc ++ではなくcであるため)任意の数の引数を取ります。

したがって、次のように呼び出すことができます。

void my_task() {
    /* do something */
}

TaskCreate(my_task);

もちろん、書くvoid my_task(void) {のも安全でしょう。cをコーディングするとき、私は個人的に「パラメーターはありません」と明示的に言うことを好みます。

最後に、*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;いくつかのキャスト魔法をやっています。

それを分析しましょう:

(int)Taskは最初にに変換Taskされますint(これは疑わしいですが、おそらく特定のアーキテクチャ/ OSには問題ありません。個人的には、long安全のためにaを使用します)。

((NewTCB->Stack) + (STACK_DEPTH-2))は、スタックNewTCB->Stack内の場所へのポインタを取得するために、いくつかの簡単な計算を実行しているだけです。TCB

*(int*)「これをに変換してから、int *それが指す場所を区別(読み取りまたは書き込み)します。

これはもっと簡単に次のように書くことができます。

int f = (int)Task;
int s = ((NewTCB->Stack) + (STACK_DEPTH-2)); /* I don't know the type of `NewTCB->Stack`, so we'll pretend 'int' for now */
int *stack_ptr = (int*)s;
*stack_ptr = f;

これはおそらくもっと明確です。

フォローアップ:構文が少し混乱することがあるので、私がどのように関数ポインターを使用する傾向があるかを指摘したいと思います。そして、このアプローチは非常に役立つと思います。基本的に、私typedefは関数ポインターのを作成し、代わりにそれを使用するのが好きです。代わりに、正しく理解する方がはるかに簡単だと思います。

例えば:

/* typedef func_t to be a pointer to a function taking no arguments and returning void */
typedef void (*func_t)(void); 

じゃあ後で...

void CreateTask(func_t task) {
    /* same work as your example, just a little easier to read */
}
于 2012-06-07T15:29:01.693 に答える
0

エヴァン・テランの答えは正しいです。コードから、タスクが実行対象として選択されたときに実行される関数へのポインターのように見えると言って、それを拡張します。

はどうかと言うと*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;

あなたの環境intでは16ビットだと思いますか?もしそうなら、これは-2になります。このコードは、タスクの「main」関数のアドレスをこの構造に保存します(これは、すでに->Taskメンバーに保存されているため奇妙ですが、おそらく正当な理由があります)

于 2012-06-07T15:34:27.563 に答える
0

*(int*)((NewTCB->Stack) + (STACK_DEPTH-2)) = (int)Task;それを取りTask、整数に変換します。NewTCB次に、のスタック (何らかの形式の配列) を見つけます。そのスタックを取り、最後から 2 番目のメンバーを見つけます。次に、それを整数変数のアドレスとして扱い、変換された Task をそのアドレスの変数に割り当てます。

NewTCB->stackC++ メンバーへのポインター構文を使用します。 はオブジェクトNewTCBへのポインターであり、オブジェクトには明らかに Stack プロパティがあります。 それに追加することは、スタック オブジェクトが動的に割り当てられた配列であることを除いて、(プレーンテキストで: : get object at index ) を記述することと同じです。lengthの 場合、index のオブジェクトは最後から 2 番目のメンバー (0 ベースのインデックス) です。 残りは、タスクを適切な場所に移動するために必要な変換を処理するだけです。 TCBTCB
STACK_DEPTH - 2(NewTCB->Stack)[STACK_DEPTH - 2]NewTCB->StackSTACK_DEPTH - 2
NewTCB->StackSTACK_DEPTHSTACK_DEPTH - 2

于 2012-06-07T15:31:42.137 に答える