![](/img/trans.png)
[英]I can't understand his typedef with pointer usage, can someone explain?
[英]I can't understand why the command 'typedef' can be used like this
我正在学习 C99 - 函数指针部分,我的教科书提供了一种使用“typedef”来简化以下代码的方法:
int (*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
↓
typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};
我知道'typedef'只能这样使用:例如。
typedef unsigned short int US;
是不是错了, int
会被(*OP_TYPE)(int,int)
,第二句是不是就变成了(*OP_TYPE)(int,int)(*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
我不明白为什么第二句话会这样。
typedef
关键字在语法上的行为类似于存储修饰符(即auto
、 register
、 static
等),但初始化部分除外。 我猜这是因为早期版本的 C 编译器在变量声明和类型别名声明之间共享代码。
因此类型别名声明和变量声明看起来或多或少相同:
static int (*A[4])(int,int); // staic variable
typedef int (*B[4])(int,int); // type alias
int (*C[4])(int,int); // local variable
我想问题是为什么一个人不能这样做:
int (*[4])(int,int) C;
我对此没有很好的答案,C 语法就是这样定义的。 我可以猜测,如果没有锚,编译器将无法正确解析类型。
那么为什么不能这样做:
(int (*[4])(int,int)) C;
回答:
它将解决缺少锚的问题。 但是,它不能使用,因为它会与强制转换运算符(type) expr
冲突。 请注意,符号C
可能在范围外定义,从而导致歧义。
int C;
{
// cast `C` to `int*` or maybe declare a pointer to `int`
(int*)C;
}
但是,有一个typeof
扩展的解决方法(即将到来的 C23 中的一个功能)。
typeof(int (*[4])(int,int)) C;
这或多或少与编译器扩展以下声明的方式相同:
typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};
to
typeof(int(*)(int,int)) p[4] = { ... }
此外,使用这个技巧可以对复杂类型进行简洁易读的声明。
typeof(int(int,int))* p[4] = { .... }
很容易看出p
是一个指向int(int,int)
函数的 4 元素数组。
是不是错了,
int
会被(*OP_TYPE)(int,int)
,第二句是不是就变成了(*OP_TYPE)(int,int)(*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};
宣言
typedef int (*OP_TYPE)(int, int);
不会改变int
的含义——它会改变OP_TYPE
的含义。
首先,一些背景:
C 中的声明分为两个主要部分:声明说明符序列,后面是逗号分隔的声明符列表。
声明器介绍被声明事物的名称,以及有关该事物的数组、函数和指针的信息。 在 typedef 中,该名称成为该类型的别名。
声明器的结构旨在反映代码中表达式的结构。 例如,假设您有一个指向int
的指针数组arr
,并且您想要访问第i
个元素指向的整数对象; 您将索引到数组并取消引用结果,如下所示:
printf( "%d\n", *arr[i] ); // *arr[i] is parsed as *(arr[i])
表达式*arr[i]
的类型是int
; 这就是为什么我们把它的声明写成
int *arr[N];
代替
int *[N] arr;
在表达式中,后缀[]
下标运算符的操作数是arr
,一元*
解引用运算符的操作数是表达式arr[i]
。 这些运算符在声明中遵循相同的优先规则,因此是上述声明的结构。
声明内容如下
arr -- arr
arr[N] -- is an array of
*arr[N] -- pointer to
int *arr[N]; -- int
因此,名为arr
的对象的类型为“指向int
的指针数组”;
同样,如果你有一个函数指针数组并且你想调用其中一个函数,你将索引到数组中,取消引用结果,然后使用任何参数调用结果函数:
x = (*p[i])(a, b);
同样,表达式(*p[i])(a, b)
的类型是int
,因此p
的声明写成
int (*p[4])(int, int);
并不是
int (*[4])(int, int) p;
同样,声明内容为
p -- p
p[4] -- is a 4-element array of
*p[4] -- pointer to
(*p[4])( ) -- function taking
(*p[4])( , ) -- unnamed parameter
(*p[4])(int, ) -- is an int
(*p[4])(int, ) -- unnamed parameter
(*p[4])(int, int) -- is an int
int (*p[4])(int, int); -- returning int
因此名为p
的对象的类型为“指向函数的数组指针,该函数采用两个int
参数并返回int
”。
到目前为止清楚吗?
那么, typedef
是如何影响这一点的呢?
让我们从没有typedef
的声明开始:
int (*OP_TYPE)(int, int);
这OP_TYPE
声明为“指向带有两个int
参数并返回int
的函数的指针”类型的对象。 如果我们添加typedef
关键字:
typedef int (*OP_TYPE)(int, int);
它改变了声明的含义,使得OP_TYPE
是类型“指向具有两个int
参数并返回int
的函数的指针”的别名。 它根本不会改变声明的结构,只会改变含义。 因此,你可以写
OP_TYPE fp;
它的含义与
int (*fp)(int, int);
其他一些例子可能有助于推动这个概念。 回到前面的例子,如果
int *ap[N];
将ap
声明为“指向int
的 4 元素数组”类型的对象,然后
typedef int *ap[N];
将ap
声明为类型“指向int
的 4 元素数组”的别名,这样
ap foo;
相当于
int *foo[N];
如果
int (*blah)[N];
将blah
声明为“指向int
的 N 元素数组的指针”类型的对象,然后声明
typedef int (*blah)[N];
将blah
声明为“指向int
的 N 元素数组的指针”类型的别名。
在您提供的示例中,
unsigned short int US;
将US
声明为unsigned short int
类型的对象; 因此,
typedef unsigned short int US;
将US
声明为unsigned short int
类型的别名。
声明(因此typedefs
)可以变得任意复杂:
int *(*(*foo())[N])(double);
foo
是一个指向函数的指针,该函数返回一个指向函数指针数组的指针,这些函数接受一个double
参数并返回一个指向int
的指针。 添加typedef
:
typedef int *(*(*foo())[N])(double);
将foo
更改为“函数返回一个指针数组的指针”类型的别名,该指针指向函数的指针数组,该函数采用double
参数并返回一个指向int
的指针;再次,
foo bar;
相当于写
int *(*(*bar())[N])(double);
int
不会被typedef
“改变”。 typedef unsigned short int US;
不是“改变” unsigned short int
,而是定义标识符US
来表示与unsigned short int
相同的类型。 同样, typedef int (*OP_TYPE)(int,int)
定义标识符OP_TYPE
以表示与int (*)(int, int)
相同的类型(指向返回int
且参数类型为 list int, int
的函数的指针)。
从语法上讲, typedef
就像一个存储类说明符,但它定义了一个“typedef 名称”而不是声明一个变量。 比较typedef int (*OP_TYPE)(int, int);
static int (*op)(int, int);
. OP_TYPE
是一个 typedef 名称,而op
是一个变量。 OP_TYPE
和op
都具有相同的类型int (*)(int, int)
。 OP_TYPE
可以在后续声明中作为类型使用,这样static OP_TYPE op;
等价于static int (*op)(int, int);
欢迎来到stackoverflow @moveityourself01!
OP_TYPE 是函数指针类型。 这是一个例子:
// This is a function
// It has a single parameter and returns
// an int
int some_func(int a) {
return(a+1);
}
int main(void) {
// regular usage of the function
printf("some_func(1) = %d\n", some_func(1));
// fun_ptr is a function pointer
// that points to the function some_func
int (*fun_ptr)(int) = &some_func;
printf("via fun_ptr->some_func(2) = %d\n", fun_ptr(2));
// create the typedef
typedef int (*funptr_type)(int);
// usage of typedef
funptr_type another_func_ptr = &some_func;
// usage of function pointer via typedef
printf("via typedef some_func(3) = %d\n", another_func_ptr(3));
return(0);
}
用法
some_func(1) = 2
via fun_ptr->some_func(2) = 3
via typedef some_func(3) = 4
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.