C语言 我不明白为什么命令“typedef”可以这样使用

xfyts7mz  于 11个月前  发布在  其他
关注(0)|答案(4)|浏览(107)

我正在学习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};
我不明白为什么第二句会是这样。

roqulrg3

roqulrg31#

关键字typedef在语法上与存储修饰符(即autoregisterstatic等)类似,但初始化部分除外。我猜这是因为早期版本的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元素数组。

zf9nrax1

zf9nrax12#

如果没有错的话,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);


同样,expression(*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声明为一个 object,类型为“指向接受两个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);
carvr3hs

carvr3hs3#

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的函数的指针,参数类型列表为int, int)。
从句法上讲,typedef类似于存储类说明符,但它定义了一个“typedef名称”而不是声明变量。比较typedef int (*OP_TYPE)(int, int);static int (*op)(int, int);OP_TYPE是typedef名称,op是变量。OP_TYPEop具有相同的类型int (*)(int, int)OP_TYPE可以用作类型在随后的声明中,使static OP_TYPE op;等效于static int (*op)(int, int);

zujrkrfu

zujrkrfu4#

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

相关问题