2012-02-20 3 views
9

少なくともtypedefと関数ポインタについて言えば、私は恐ろしい "偶発的プログラマ"病に苦しんでいるかもしれないと思います。だから私は、私が得たすべての出力に基づいて結果を分析するためにこれらを含むあらゆる種類の組み合わせを試してきました。typedefがどのように関数ポインタに作用するか

しかし、私はさまざまな組み合わせを試し続けましたが、結果を分析する代わりに、私は今やプロセスで失われています。

私はあなたがこの混乱を把握するのを手伝ってくれることを願っています。

最初のコード例

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print *pr; 
pr = &do_something; 
pr(); // Hello World 

2番目のコード例上記のコード例の両方が動作するにはどうすればよい

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print *pr; 
pr = do_something; 
pr(); // Hello World 

'&' は、関数名には影響しないかのように、それはだ

第3コード例

typedef void (print)(void); 
void do_something (void) { printf("Hello World\n"); } 

print pr; 
pr = do_something; // compile error 
pr = &do_something; // compile error 
pr(); 

私はここで働いてますがいまいましいするには、上記の割り当てのいずれかを期待していました!私は実際には関数ポインタ(と多分typedefも)を理解していない。

+1

これは役立つ可能性がありますhttp://stackoverflow.com/questions/4298654/operator-optional-in-function-pointer-assignment –

+0

うーん...私はあなた自身 'エキスパートCプログラミング'それはexplans Cのvar規則を定義する。私はそれをあなたのためにオンラインで見つけようとします – shengy

+1

ちょうどGoogleのエキスパートCのプログラミング、最初の1つは本です。 「どのように宣言が成立したか」を検索すれば、最初の票が下降詞であることを夢中にしている答えが – shengy

答えて

18

ファンクション名のアドレスとプレーン関数名の両方が同じ意味であるため、&は関数名には影響しません。

#include <stdio.h> 
typedef void print(void); 
static void dosomething(void) { printf("Hello World\n"); } 

int main(void) 
{ 
    print *f1 = dosomething; 
    print *f2 = &dosomething; 
    f2(); 
    (f1)(); 
    (*f1)(); 
    (**f2)(); 
    (***f1)(); 
    (****f2)(); 
    (*****f1)(); 
} 

の下にきれいにコンパイルされます:関数ポインタを使用している場合

は同様に、複数の参照解除は問題ではありません、私は複数の星が良いスタイルであることを主張しないでしょう

gcc -O3 -g -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \ 
    -Wold-style-definition -std=c99 xx.c -o xx 

。そうではありません。それは「奇妙なことであり、あなたはそれを言うかもしれません。1つは十分です(そして1つ星は主に私のような人のためにCでプログラミングすることを学びました。標準の前に "(*pointer_to_function)(arg1, arg2)表記を使わずにポインタを使って関数を呼び出すことはOKです;あなたが好きなら" pointer_to_function(arg1, arg2) " )。はい、それは変です。いいえ、他のタイプ(または種類のクラス)は同じ動作を示しません。よろしくお願いします。

+1

これは奇妙なことです。試して実際にコンパイルする。 :) –

+4

+1、明らかにするために、関数と関数ポインタは同じではありませんが、前者はほとんどの文脈で(後者は自動的に)後者に崩壊する傾向があります。式 '** f2'では、関数ポインタが逆参照され、結果として得られた関数は直ちにポインタに戻ってポインタに戻り、再び参照解除されます。 – avakar

+2

配列には、同じではありませんが、「自動減衰」の動作があります。 'int x [10];'の場合、 'x'と'&x'のアドレスは同じです。しかし、彼らのタイプは異なります、そして、あなたはここに示された素敵な星の塔を使用することはできません。 – ugoren

3

C/C++では、funcname&funcnameの両方がアドレスfuncnameとなり、関数ポインタ変数に割り当てることができます。これは、実際には、構文がどのように言語のために設計されたかのちょうど奇妙なものです。

7

関数ポインタについてのことは、関数であることです。ポインタ!

#include <stdio.h> 
typedef void (*print)(void); 
//   ^
void do_something (void) { printf("Hello World\n"); } 
int main (void) { 
    print pr; 
    pr = do_something; // &do_something would also work. 
    pr(); 
    return 0; 
} 

あなたがfuncName&funcNameを使用するかどうかという点で、それは問題ではありません(Cで少なくとも):この:-)はあなたの第三のサンプルは、仕事を得る方法です。セクション6.3.2.1 Lvalues, arrays and function designatorsの状態は、

です。関数指定子は、関数型を持つ式です。 sizeof演算子のオペランドまたは単項演算子の場合を除き、 "関数戻り型"型の関数指定子は、 "関数戻り型へのポインタ"型の式に変換されます。

+0

になると思います。 -/ –

3

Cと同様に、C++には関数へのポインタがあります。void (*)()たとえば、引数をとらず値も返さない関数へのポインタです。しかし、C++は関数void (&)()への参照を導入しており、2つの間の暗黙的な変換もあります(ルールは正確に覚えていませんが)。

したがって:

  • funcname
  • &funcnameを関数への参照であり、オーバーロードされたアドレス(または参照)を取る機能が必要であること

注関数へのポインタです正確なタイプ(過負荷を解決するため)にstatic_castを入力します。

関連する問題