繁体   English   中英

我不明白为什么命令'typedef'可以这样使用

[英]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关键字在语法上的行为类似于存储修饰符(即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 元素数组。

是不是错了, 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_TYPEop都具有相同的类型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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM