chow1340
chow1340

Reputation: 13

typedef - Typedef without curly braces

I'm rather new at C, but what does this syntax mean?

typedef Value (*NativeFn)(int argCount, Value* args);

From what I understand, "Value" is used here to define the type of the new name. The part I don't understand is (*NativeFn)(int argCount, Value* args); , what does this part mean?

Upvotes: 0

Views: 206

Answers (4)

reyad
reyad

Reputation: 1432

Well,

typedef (*NativeFn)(int argCount, Value* args)

means

NativeFn is a function type(can also be called "a pointer to function" or "function pointer") that returns Value and takes a int and a Value * as arguments.

If you've troubling undertsanding why and how should we use it, then read the code below, specially the comments, it'll be clear to you, what (*NativeFn)(int argCount, Value* args) means and how to use it:

#include <stdio.h>

// note: "Value" is a type declared earlier
//       for discussions sake we're declaring our own Value type

typedef struct __value {
    int x, y;
} Value;


// now, the following tells us that:
// "NativeFn" is some function type that returns "Value"
typedef Value (*NativeFn)(int argCount, Value* args);


// okay, see how to use "NativeFn"
// for use "NativeFn" we've to declare some function first
// which takes two arguments same as "NativeFn" and return "Value"
Value someFun(int argCount, Value* args) {
    // do something argCount and args
    // at last it should return some "Value" type
    Value v = {2, 3};
    return v;
}

int main() {
    // now its time to use "NativeFn"
    NativeFn fun;

    fun = someFun; // notice we can use fun as a variable and assign a
    // function to it, which must take arguments same as "NativeFn" and returns "Value" type

    Value input = {10, 12};
    
    Value output = fun(1, &input); // note, we're calling "fun", not "someFun"

    // it'll output 2, 3, cause we're returning Value v = {2, 3} from "someFun"
    printf("(x, y): %d, %d\n", output.x, output.y);
    
    return 0;
}

If you've any question, ask me in the comment...

Upvotes: 0

Keith Thompson
Keith Thompson

Reputation: 263307

Others have correctly said that this:

typedef Value (*NativeFn)(int argCount, Value* args);

creates a typedef name NativeFn for a pointer-to-function type.

The syntax of typedef, like the syntax of C declarations in general, can be confusing. The typedef feature was actually added to the language after the declaration syntax had been established, and it had to be added without breaking anything else. The solution was to treat typedef syntactically like a storage class specifier (though it isn't one semantically). The storage class specifiers other than typedef are extern, static, _Thread_local, auto, and register.

Which means that you can understand a typedef declaration by replacing the keyword typedef by, for example, static. Where a static declaration declares an object (or function) of a certain type, a corresponding typedef declaration creates a type definition with the same name and type. So this:

static int foo;

creates an object foo of type int (with static storage duration), while this:

typedef int foo;

creates a type name foo that's an alias for type int.

So if your declaration had been:

static Value (*NativeFn)(int argCount, Value* args);

it would have defined NativeFn as a pointer-to-function object (with the function returning a result of type Value). Replacing static by typedef means that NativeFn is a type name that refers to that same pointer-to-function type.

It's also important to remember that typedef does not create a new type. It creates a new name for an existing type.

Upvotes: 1

John Bode
John Bode

Reputation: 123468

The typedef facility is used to create aliases for types. For example,

typedef int *iptr;

creates the name iptr as a synonym for the type int *, so you could declare pointers using

iptr p, q;

instead of writing

int *p, *q;

C declaration syntax is a bit more complicated than most people realize, especially where pointers are involved. The basic rules are:

T *p;            // p is a pointer to T
T *a[N];         // a is an array of pointer to T
T *f();          // f is a function returning pointer to T
T (*a)[N];       // a is a pointer to an array of T
T (*f)();        // f is a pointer to a function returning T
T const *p;      // p is a pointer to const T
const T *p;      // same as above
T * const p;     // p is a const pointer to T

Things can get arbitrarily complicated - you can have arrays of pointers to functions:

T (*a[N])();

or functions returning pointers to arrays:

T (*f())[N];

or even worse atrocities. Function pointer declarations get uglier when there are parameters in the mix; fortunately, you only need to list the parameter types in a declaration, not the names:

typedef Value (*NativeFn)(int, Value*);

makes things a little easier to follow.

That declaration creates NativeFn as a synonym for the type "pointer to function taking an int and Value * and returning Value".

Suppose you have a function defined as

Value foo( int argcCount, Value *args )
{
  Value result;
  ...
  return result;
}

If you want to create a pointer to this function named fptr, you'd normally declare it as

Value (*fptr)(int, Value *) = foo;

However, the typedef declaration above allows you to write

NativeFn fptr = foo;

Having said all that, use typedef sparingly. The problem is that while it can create an easier-to-read ways of declaring some items, it also hides some potentially useful information. For example, despite the iptr example above, it's best to not hide pointers behind typedefs - if someone needs to use the unary * operator on p or q in order to use them properly, than that information needs to be in the declaration of those items. If someone ever needs to call the thing fptr points to, then they need to know what the return type is, the number and types of parameters, etc., but all that information is missing in the declaration that uses the typedef name.

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Consider such a record

Value (int argCount, Value* args)

It denotes a function type that has the return type Value and two parameters of the type int and Value *.

The identifier Value is declared somewhere else and can for example be an alias for a type.

To introduce an alias for a pointer type to the function type you can write

typedef Value (*NativeFn)(int argCount, Value* args);

So if you have a function as for example

Value some_function(int argCount, Value* args);

then you can declare a pointer to this function using the typedef alias definition the following way

NativeFn pointer_to_some_function = some_function; 

Upvotes: 0

Related Questions