5

I understand that typedef can be used to define a new custom type, for example:

// simple typedef
typedef unsigned long ulong;

// the following two objects have the same type 
unsigned long l1;
ulong l2;

I recently came across this typedef, and got lost in deciphering what is going on in the declaration:

typedef int16_t CALL_CONVENTION(* product_init_t)(product_descript_t *const description)

Can someone guide me and explain what this is doing?

EDIT: changed NEW_TYPE to CALL_CONVENTION. It's a define. Thanks for spotting that out.

nikk
  • 2,627
  • 5
  • 30
  • 51

3 Answers3

10

It declares type product_init_t as a pointer to a function which

  • takes parameter product_descript_t *const description;
  • returns int16_t;
  • uses calling convention CALL_CONVENTION (as @M.M suggested even when it was misnamed).

P.S. Since "a complete answer in 2016 should show the modern way to write this type-alias" (@Howard Hinnant), here it is:

using product_init_t = int16_t (CALL_CONVENTION *)(product_descript_t *const description);
AlexD
  • 32,156
  • 3
  • 71
  • 65
  • 2
    it's likely that `NEW_TYPE` is a linkage or calling convention specifier; not a part of the return type – M.M May 31 '16 at 21:04
  • 1
    @M.M Likely, but then the name is somewhat confusing. Anyway, added to the answer. Thanks! – AlexD May 31 '16 at 21:05
  • @M.M you are right. I have made the edit to the post. – nikk May 31 '16 at 21:12
  • Ok thanks. This CLEARLY helps me understand the problem. Accepting as answer. One last thing, I am fairly new to compiler infrastructure, so if you an point me to a web link on dealing with Calling Conventions for these type of statements, I'll truly appreciate it. – nikk May 31 '16 at 21:48
  • A complete answer in 2016 should show the modern way to write this *type-alias* which imho is much cleaner. – Howard Hinnant Jun 01 '16 at 01:50
  • @HowardHinnant As you wish :). – AlexD Jun 01 '16 at 19:38
3

Here is how to make sense of complicated typedefs: First look at the line with typedef taken out:

int16_t NEW_TYPE (* product_init_t)(product_descript_t *const description);

Then work out what this line would declare: it's a variable called product_init_t with a certain type.

Finally, adding typedef means that it declares product_init_t to be an alias for that certain type, instead of a variable of that type.


To work out the above declaration, you can use cdecl , or you can attack it from the outside-in using knowledge of the possible declarators (pointer, array, function).

In this case the outer-most feature is the parameter list at the right, so we suspect this might be a function declarator. Function declarators look like (roughly):

returntype    function_name   (parameters_opt)

although bear in mind that a common compiler extension is to specify additonal properties of the function via __declspec or otherwise, in the same place as the return type; or there might be extern "C" there, and so on.

So far we are at the stage that (*product_init_t) is a function with int16_t NEW_TYPE as return type (and possible declspecs), and parameter list (product_descript_t *const description).

Finally, * product_init_t is just a pointer declarator, so we conclude that product_init_t is a pointer to a function of the above type.

Your comments indicate being unsure about NEW_TYPE. It will be something that is already defined earlier (or a compiler extension keyword); perhaps preprocessing the code with gcc -E would help if your IDE can't find its definition.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • The correct line is `typedef int16_t CALL_CONVENTION(* product_init_t)(product_descript_t *const description)` where CALL CONVENTION is defined in `ifdef __amd64__ define CALL_CONVENTION else define CALL_CONVENTION __attribute__((__cdecl__)) endif` how will this now make a difference? – nikk May 31 '16 at 21:39
1

It is an interesting example of difference between #define and typedef usage.

#define FX_TYPE void (*)(int)
typedef void (*stdfx)(int);

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */

please see here

Therefore in case of following:

typedef int16_t CALL_CONVENTION(* product_init_t)(product_descript_t *const description)

We can use the above typedef as follows:

void fx_typ(product_init_t fx);

fx is a pointer to function which takes product_descript_t *const description as argument and returns int16_t.

The use of CALL_CONVENTION is confusing, however, it can be suppressed by empty macro as follows:

#define  CALL_CONVENTION

Note: the above micro has no body. In my view, CALL_CONVENTION just adds to confusion.

Community
  • 1
  • 1
Vivek
  • 357
  • 1
  • 18
  • Good point, @vivek. CALL CONVENTION is actually defined as empty (for the most part) in my example. I wonder what is the point. – nikk Jun 01 '16 at 04:09