typedef int (fc_name) (void);
ここに fc_name
は任意の有効なC記号です。
これは関数ポインタtypedef
とどのように異なりますか?
これは、関数型に対するtypedef
です。目的は関数ポインタに使用することですが、この場合、使用する構文は次のようになります。
int bar(void);
fc_name* foo = bar; /* Note the * */
更新: Jonathan Lefflerの回答 へのコメントで述べたように、typedef
を使用して関数を宣言できます。 1つの用途は、コールバック関数のセットを宣言することです。
typedef int (callback)(int, void*);
callback onFoo;
callback onBar;
callback onBaz;
callback onQux;
最初の括弧は不要です-これは次と同等です:
_typedef int fc_name(void);
_
GCCにそれ自体で文句を言わせることはできませんが、これは何の役にも立たないと思います。
これは、_fc_name
_が、引数をとらずにint
を返す関数型のエイリアスであることを意味します。たとえば、次のコマンドを使用してRand()
関数を宣言することはできますが、それほど便利ではありません。
_fc_name Rand;
_
関数定義でtypedef
を使用することはできません。
関数typedefへのポインタは次のようになります。
_typedef int (*fc_name)(void);
_
このコードは、アスタリスクのないtypedefが関数ポインターではないことを示しています(現在削除されている代替回答に対応しています)。
_static int function(void)
{
return 0;
}
typedef int fc_name1 (void);
typedef int (fc_name2)(void);
typedef int (*fc_name3)(void);
fc_name1 x = function;
fc_name2 y = function;
fc_name3 z = function;
_
コンパイルすると、「gcc」は次のように言います。
_gcc -Wextra -Wall -pedantic -c -O x.c
x.c:10:1: error: function ‘x’ is initialized like a variable
x.c:11:1: error: function ‘y’ is initialized like a variable
_
そして、このコードは、 jamesdlin :によって提案されているように、実際に_fc_name *var = funcname;
_を使用できることを示しています。
_static int function(void)
{
return 0;
}
typedef int fc_name1 (void);
typedef int (fc_name2)(void);
typedef int (*fc_name3)(void);
fc_name1 x_0 = function;
fc_name1 *x_1 = function;
fc_name2 y_0 = function; // Damn Bessel functions - and no <math.h>
fc_name2 *y_1 = function; // Damn Bessel functions - and no <math.h>
fc_name3 z = function;
_
Y0を使用して、y1はGCC警告を生成します。
_x.c:12:11: warning: conflicting types for built-in function ‘y0’
x.c:13:11: warning: built-in function ‘y1’ declared as non-function
_
そして、 schot からのコメントに基づいて構築します:
_static int function(void)
{
return 0;
}
typedef int fc_name1 (void);
typedef int (fc_name2)(void);
typedef int (*fc_name3)(void);
fc_name1 x_0 = function; // Error
fc_name1 *x_1 = function; // x_1 is a pointer to function
fc_name1 x_2; // Declare int x_2(void);
fc_name1 *x_3 = x_2; // Declare x_3 initialized with x_2
fc_name2 y_0 = function; // Damn Bessel functions - and no <math.h>
fc_name2 *y_1 = function; // Damn Bessel functions - and no <math.h>
fc_name1 y_2; // Declare int y_2(void);
fc_name1 *y_3 = x_2; // Declare y_3 initialized with y_2
fc_name3 z = function;
_
興味深い-Cの暗いコーナーは確かに暗いです。
これがtypedef nameに対して行われるのを見たことがありませんが、functionの名前を括弧で囲むと、関数のようなマクロとして展開されるのを防ぐのに役立ちます。同名。たとえば、isxxx
関数はctype.h
は、関数とマクロの両方として定義されています。これは、isalpha
へのポインタを取ることができるようにするためです。しかし、Cライブラリはどのようにdefineアウトオブラインisalpha
?おそらくこのように:
#include <ctype.h>
int
(isalpha)(int c)
{
return isalpha(c);
}
関数本体でのisalpha
の使用はマクロとして拡張されますが、関数ヘッダーでの使用は拡張されません。
面白い! typedef宣言は、ストレージクラスとしてtypedefを使用する宣言です。
typedef int fc_name1 (void);
// this defines a function type called fc_name1
// which takes no parameter and returns int
後で、次のような関数を定義できます。
fc_name1 myFunc;
// this is equivalent to the next line
// int myFunc(void);
これはc/c ++標準から理解できるはずです。
正しい形式は次のとおりです。
typedef int (*myfunc)(void);
次のような関数を定義できます。
int helloword(void) {
printf("hello, world\n");
}
次に、この関数への変数ポイントを定義します。
myfunc hw_func;
hw_func = helloworld;
関数ポインタで関数を呼び出します。
int ret = (*hw_func)();
関数ポインタが必要な理由は、C言語には事前定義された関数ポインタがなく、void *
ポインタを使用して関数を呼び出すことはC言語では違法であるためです。
1 #include <stdio.h>
2
3
4 typedef int (fc_name)(void);
5
6
7
8 int test_func1 ()
9 {
10 printf("\n test_func1 called\n");
11
12 return 0;
13 }
14
15 int test_func2 (void)
16 {
17 printf("\n test_func2 called\n");
18 return 0;
19 }
20
21 int handler_func(fc_name *fptr)
22 {
23 //Call the actual function
24 fptr();
25 }
26
27 int main(void)
28 {
29 fc_name *f1, *f2;
30
31 f1 = test_func1;
32 f2 = test_func2;
33
34 handler_func(f1);
35 handler_func(f2);
36
37 printf("\n test complete\n");
38
39 return 0;
40 }
出力:-
test_func1 called
test_func2 called
test complete
したがって、私が質問したtypedef(ここでは4行目)は関数型を表しており、関数ポインターtypedefと同じではありません。この種のtypedefはあまり重要ではありません。これらは、スタイルの標準として、または単に意図的に難読化を作成するために使用されます;-)