typedef void (*fp_type)(void);
declares fp_type
as a function pointer; so, fp_type fp;
makes fp
a function pointer, and that's how it's going to behave if you invoke it. A function pointer is a variable, and as a global variable (extern
) would normally be expected to be in the data section, as a pointer variable whose contents then refers to some function (in text/code). So, the compiler is going to fetch the value of the pointer variable and then make an indirect call with that.
If that label provided in the assembly part is not a pointer to code, it will mess up, and either the C code or the assembly code should change so they both agree on whether the label is code (a function) or data (a function pointer variable).
In C, you don't need to dereference a function pointer; simply applying invocation will implicitly dereference it. So, fp();
and (*fp)()
are the same and both will access that function pointer variable to obtain its contents: the function address, as well as invoke the function referred to by that address (via indirect function call).
If it is just a function (and not a function pointer) then declare it so: typedef void f_type(void);
and f_type f;
. With that, f();
will simply invoke the function without accessing any variable (and (*f)();
will do the exact same; the dereference is effectively ignored there).
If it was me and all we wanted was to invoke assembly from C, I would forgo the unnecessary typedef and function pointer local variable in main
, and simply declare the function: extern void _exit(void);
, later invoking as _exit();
.
Nominally, even if you want the function pointer local variable in main
, I would declare _exit
as would seem more proper: extern void _exit(void);
— and you can still use the function pointer if want that (exit_f exit = _exit;
)
In any case, that cast (exit_f)
, as applied in ... = (exit_f) _exit
, is unnecessary, and good to avoid unnecessary casts, as that will help the compiler give errors/warnings on typos and such.