Home > Enterprise >  I can't understand why the command 'typedef' can be used like this
I can't understand why the command 'typedef' can be used like this

Time:05-25

I was studying C99 - Function pointer part and my textbook offered a way to use 'typedef' for simplifying the code below :

int (*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};

typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};

I've known that 'typedef' can be used only like this : eg.

typedef unsigned short int US;

Was it not wrong, int would be altered as (*OP_TYPE)(int,int), and Isn't it right the second sentence become (*OP_TYPE)(int,int)(*p[4])(int,int) = {&Sum,&Sub,&Mul,&Div};

I can't understand why the second sentence could be like that.

CodePudding user response:

The typedef keyword behaves grammatically like storage modifiers (i.e. auto, register, static etc) except the initialization part. My guess the reason for that is that the early versions of C compilers shared code between variable declaration and type alias declarations.

Therefore the type alias declaration and variable declaration look more or less the same:

static  int (*A[4])(int,int); // staic variable
typedef int (*B[4])(int,int); // type alias
        int (*C[4])(int,int); // local variable

I guess the question is why one cannot do:

int (*[4])(int,int) C;

I have no good answer to that, C grammar is simply defined this this way. I can guess that without the anchor the compiler cannot correctly parse the type.

So why one can't do:

(int (*[4])(int,int)) C;

Answer:

It would solve the problem with missing anchor. However, it cannot be used because it will conflict with cast operator (type) expr. Note that symbol C may be defined on out scope resulting in ambiguity.

int C;
{
  // cast `C` to `int*` or maybe declare a pointer to `int`
  (int*)C;
}

However, there is a workaround with typeof extension (a feature in upcoming C23).

typeof(int (*[4])(int,int)) C;

This is more or less the same how the compiler expands the following declaration:

typedef int (*OP_TYPE)(int,int);
OP_TYPE p[4]={&Sum,&Sub,&Mul,&Div};

  to

typeof(int(*)(int,int)) p[4] = { ... }

Moreover, using this trick allows a neat and readable declaration of complex types.

typeof(int(int,int))* p[4] = { .... }

It is easy to see that p is a 4-element array of pointers to int(int,int) function.

CodePudding user response:

int is not "altered" by a typedef. typedef unsigned short int US; is not "altering" unsigned short int, it is defining the identifier US to denote the same type as unsigned short int. Likewise, typedef int (*OP_TYPE)(int,int) is defining the identifier OP_TYPE to denote the same type as int (*)(int, int) (a pointer to a function returning int with parameter type list int, int).

Syntactically, typedef is like a storage class specifier but it defines a "typedef name" instead of declaring a variable. Compare typedef int (*OP_TYPE)(int, int); to static int (*op)(int, int);. OP_TYPE is a typedef name and op is a variable. OP_TYPE and op both have the same type int (*)(int, int). OP_TYPE can be used as a type in subsequent declarations, so that static OP_TYPE op; is equivalent to static int (*op)(int, int);

CodePudding user response:

Welcome to stackoverflow @moveityourself01!

OP_TYPE is a function pointer type. Here is an example:

// 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);

}

Usage

some_func(1) = 2
via fun_ptr->some_func(2) = 3
via typedef some_func(3) = 4
  • Related