code2be
code2be

Reputation: 1378

How to use this defined type in C?

How can I use this defined type ?

typedef void (*(workers[2]))(char *, char *, int);

What I could understand, that I'll have workers, which is an array of two pointers, each one points to a void, which accepts the mentioned arguments.

Is that correct ?

Trial #1

void worker1(char * x, char * y, int z) {

}

void worker2(char * x, char * y, int z) {

}

and then inside some another void, I did:

workers w;
w[0] = worker1;
w[1] = worker2;

Compiling, I get: error: cannot convert `void (**)(char*, char*, int)' to `void (* (*)[2])(char*, char*, int)'

Upvotes: 1

Views: 91

Answers (2)

thb
thb

Reputation: 14454

Suppose:

typedef void (*(workers[2]))(char *, char *, int);
workers my_workers;

The workers is a type (really, an alias for a type). The my_workers is an object of the workers type.

The my_workers is an array of two pointers, each pointing to a function. Each such function accepts the mentioned arguments and returns void.

TRIAL

As your request, I have tried your code as follows.

#include <stdio.h>

typedef void (*(workers[2]))(char *, char *, int);

void worker1(char * x, char * y, int z) {
    printf("1: [%s] [%s] [%d]\n", x, y, z);
}

void worker2(char * x, char * y, int z) {
    printf("2: [%s] [%s] [%d]\n", x, y, z);
}

int main() {
    char sa[] = "here";
    char sb[] = "there";
    char sc[] = "everywhere";
    char sd[] = "nowhere";
    workers w;
    w[0] = worker1;
    w[1] = worker2;
    (w[0])(sa, sb, 50);
    (w[1])(sc, sd, 70);
    return 0;
}

Try that. For me, it compiles and runs with no warnings, no errors.

Upvotes: 1

John Bode
John Bode

Reputation: 123448

workers is an alias for the type "2-element array of pointers to functions taking two char * and an int as arguments and returning void".

Here's an example of what this beast might look like in practice.

void f0( char *foo, char *bar, int bletch )
{
  // do something interesting with foo, bar, and bletch
}

void f1( char *foo, char *bar, int bletch )
{
  // do something else interesting with foo, bar, and bletch
}

int main( void )
{
  workers w = { f0, f1 }; // equivalent to void (*w[2])(char *, char *, int ) = { f0, f1 };

  // call f0 through w:
  w[0]( "blah", "blah", 1 );

  // call f1 through w:
  w[1]( "ugh", "blah", 2 );
  ...
}

The workers typedef basically creates a shorter name for a complicated, hard-to-read type. In practice, it would probably be better to create a typedef for just the function type, then create an array of that:

typedef (*worker)(char *, char *, int );
worker w[2] = { f0, f1 };

The problem with a declaration like

workers w = { f0, f1 };

is that it's not immediately obvious that w has an array type, so the initialization looks confusing. It also relies on the person using this type to know that it's an array type of a certain size. We call that a "leaky abstraction", and they lead to confusion and maintenance headaches.

You still have to know that each w[i] is a function type that takes a certain number and type of arguments, so ideally that should be hidden behind an interface as well (i.e., you pass w[i] to a function that knows how to call it, rather than calling it yourself).

Upvotes: 3

Related Questions