Understanding how to use typedef void function with pointers as params
Asked Answered
C

5

5

I'm trying to understand a firmware written in C that drives a chip for ultrawideband connections.

The firmware does heavy use of typedef and pointers. I've understood most of the idea behind the firmware but there's a typedef void function I can't understand.

Basically, the firmware creates a structure to hold the device data with

typedef struct
{
   //some data
   dwt_cb_t    cbTxDone; // Callback for TX confirmation event
   //some other data
} dwt_local_data_t ;

I've understood that the structure is named dwt_local_data_t and contains some variables including this strange dwt_cb_t type.

On the .h file dwt_cb_t is named as

// Call-back type for all events    
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

where dwt_cb_data_t is another structure in the form of

typedef struct
{
    uint32 status;      //initial value of register as ISR is entered
    uint16 datalength;  //length of frame
    uint8  fctrl[2];    //frame control bytes
    uint8  rx_flags;    //RX frame flags, see above
} dwt_cb_data_t;

Now, I'm trying to understand the meaning of typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

From what I've understood, typedef void is a pointer-to-function type. It defines a variable dwt_cb_t that points to a function receiving as an input a constant struct dwt_cb_data_t

I don't know if my reasoning is correct because I can't understand why there's a * spaced at the end of dwt_cb_data_t. Does it mean that the input of the function is the pointer of the structure? In this case, why don't write typedef void (*dwt_cb_t)(const *dwt_cb_data_t); instead?

Consultation answered 22/10, 2020 at 8:2 Comment(3)
Because const *dwt_cb_data_t is not a valid declaration for a parameter? Why do you think this should be equivalent to const dwt_cb_data_t*?Goldstein
typedefs never define variables, they define types. You're right about the meaning of parameter, but I'm confused why you think const *dwt_cb_data_t is legal syntax. A pointer to T is always written T* not *T.Jehu
@Goldstein @Jehu I missed out the fact that the variable type is const dwt_cb_data_t and not only const. It makes sense now to put * at the very endConsultation
C
4

To make it more clear let's assume that there is a function declared like

void f( int *x );

The type of the function is void( int * ).

You can introduce an alias for this function type like

typedef void Func( int * );

and declare (but not define) the function using the alias

Here is a demonstrative program.

#include <stdio.h>

typedef void Func( int * );

Func f;

int main(void) 
{
    int x = 0;
    
    printf( "x = %d\n", x );
    
    f( &x );

    printf( "x = %d\n", x );
    
    return 0;
}

void f( int *x )
{
    ++*x;
}

The program output is

x = 0
x = 1

Pay attention to that you could also declare the function alias the following way

void typedef Func( int * );

Now let's declare an alias for a function pointer to the function type.

You could write simply

typedef void Func( int * );

and

typedef Func *FuncPtr;

Here is a demonstrative program.

#include <stdio.h>

typedef void Func( int * );

Func f;

typedef Func *FuncPtr;

int main(void) 
{
    int x = 0;
    
    printf( "x = %d\n", x );
    
    FuncPtr fp = f;

    fp( &x );

    printf( "x = %d\n", x );
    
    return 0;
}

void f( int *x )
{
    ++*x;
}

On the other hand, you could declare an alias for a pointer to the function type without using the alias for the function type.

#include <stdio.h>

typedef void Func( int * );

Func f;

typedef void ( *FuncPtr )( int * );

int main(void) 
{
    int x = 0;
    
    printf( "x = %d\n", x );
    
    FuncPtr fp = f;

    fp( &x );

    printf( "x = %d\n", x );
    
    return 0;
}

void f( int *x )
{
    ++*x;
}

Now compare these declarations of aliases

typedef void ( *FuncPtr )( int * );
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

The only difference is the types of parameters. In the first declaration the type of the parameter is int * while in the second declaration the type of the parameter is const dwt_cb_data_t *.

In C++ along with typedef(s) you may use using declarations as for example

using dwt_cb_t = void (*)(const dwt_cb_data_t *);

Using the alias declaration in C++ is more flexible because you can use template alias declarations.

Here is a demonstrative program.

#include <iostream>

template <typename T>
using FuncPtr = void ( * )( T * );

template <typename T>
void f( T *t )
{
    ++*t;
}

int main() 
{
    FuncPtr<int>  fp1 = f;
    FuncPtr<char> fp2 = f;
    
    int x = 0;
    char c = 'A';
    
    fp1( &x );
    fp2( &c );
    
    std::cout << "x = " << x << '\n';
    std::cout << "c = " << c << '\n';
    
    return 0;
}

The program output is

x = 1
c = B
Conventicle answered 22/10, 2020 at 8:56 Comment(0)
G
6

Stop thinking in terms of typedef void. You are truncating the definition this way.

The symbol defined is dwt_cb_t and is an alias for the type void (*)(const dwt_cb_data_t *) which is: pointer to function taking const dwt_cb_data_t * parameter and returning void.

In C++ you would write:

using dwt_cb_t = void (*)(const dwt_cb_data_t *);

which is much clear.

Greenwood answered 22/10, 2020 at 8:6 Comment(0)
C
4

To make it more clear let's assume that there is a function declared like

void f( int *x );

The type of the function is void( int * ).

You can introduce an alias for this function type like

typedef void Func( int * );

and declare (but not define) the function using the alias

Here is a demonstrative program.

#include <stdio.h>

typedef void Func( int * );

Func f;

int main(void) 
{
    int x = 0;
    
    printf( "x = %d\n", x );
    
    f( &x );

    printf( "x = %d\n", x );
    
    return 0;
}

void f( int *x )
{
    ++*x;
}

The program output is

x = 0
x = 1

Pay attention to that you could also declare the function alias the following way

void typedef Func( int * );

Now let's declare an alias for a function pointer to the function type.

You could write simply

typedef void Func( int * );

and

typedef Func *FuncPtr;

Here is a demonstrative program.

#include <stdio.h>

typedef void Func( int * );

Func f;

typedef Func *FuncPtr;

int main(void) 
{
    int x = 0;
    
    printf( "x = %d\n", x );
    
    FuncPtr fp = f;

    fp( &x );

    printf( "x = %d\n", x );
    
    return 0;
}

void f( int *x )
{
    ++*x;
}

On the other hand, you could declare an alias for a pointer to the function type without using the alias for the function type.

#include <stdio.h>

typedef void Func( int * );

Func f;

typedef void ( *FuncPtr )( int * );

int main(void) 
{
    int x = 0;
    
    printf( "x = %d\n", x );
    
    FuncPtr fp = f;

    fp( &x );

    printf( "x = %d\n", x );
    
    return 0;
}

void f( int *x )
{
    ++*x;
}

Now compare these declarations of aliases

typedef void ( *FuncPtr )( int * );
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

The only difference is the types of parameters. In the first declaration the type of the parameter is int * while in the second declaration the type of the parameter is const dwt_cb_data_t *.

In C++ along with typedef(s) you may use using declarations as for example

using dwt_cb_t = void (*)(const dwt_cb_data_t *);

Using the alias declaration in C++ is more flexible because you can use template alias declarations.

Here is a demonstrative program.

#include <iostream>

template <typename T>
using FuncPtr = void ( * )( T * );

template <typename T>
void f( T *t )
{
    ++*t;
}

int main() 
{
    FuncPtr<int>  fp1 = f;
    FuncPtr<char> fp2 = f;
    
    int x = 0;
    char c = 'A';
    
    fp1( &x );
    fp2( &c );
    
    std::cout << "x = " << x << '\n';
    std::cout << "c = " << c << '\n';
    
    return 0;
}

The program output is

x = 1
c = B
Conventicle answered 22/10, 2020 at 8:56 Comment(0)
V
1

Does it mean that the input of the function is the pointer of the structure?

Yes, it indicates that the parameter of the function is a pointer to the struct.

In this case, why don't write

typedef void (*dwt_cb_t)(const*dwt_cb_data_t);

instead?

This because the pointer symbol * has to be placed before an identifier, and not before type of the identifier. In this case you can see the function as this:

typedef void (*dwt_cb_t)(const dwt_cb_data_t *var);

The only thing is that var is omitted.

Vannesavanness answered 22/10, 2020 at 8:8 Comment(1)
I was missing that const dwt_cb_data_t was the actual type and the variable was omitted; now it makes a lot more senseConsultation
W
1

Now, I'm trying to understand the meaning of typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

means, define a type dwt_cb_t which is a pointer to a function which returns void and accepts one argument of type const dwt_cb_data_t *.

If you have a function, like

 void func(const dwt_cb_data_t * data); // func accepts argument type 
                                           const dwt_cb_data_t * , returns void 

you can write

 dwt_cb_t f = func;
Willettewilley answered 22/10, 2020 at 8:9 Comment(0)
G
0
typedef void (*dwt_cb_t)(const dwt_cb_data_t *);

This just means that dwt_cb_data_t is a datatype and dwt_cb_data_t * is nothing more that a pointer to it.

The function prototype is simply lacking it's formal parameter name, which is fine. A stepped down version of this would be :

int myFunc(int, char*);  // no formal parameter name, just its datatype

And then later on, in it's implementation, you would see

int myFunc(int var1, char* var_ptr){
//function body 
}

It is just easier to read without the parameter name.

Greco answered 30/10, 2020 at 7:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.