32

I have a struct that contains a declaration like this one:

void (*functions[256])(void) //Array of 256 functions without arguments and return value

And in another function I want to define it, but there are 256 functions! I could do something like this:

struct.functions[0] = function0;
struct.functions[1] = function1;
struct.functions[2] = function2;

And so on, but this is too tiring, my question is there some way to do something like this?

struct.functions = { function0, function1, function2, function3, ..., };

EDIT: Syntax error corrected as said by Chris Lutz.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0x77D
  • 1,564
  • 2
  • 18
  • 17

6 Answers6

31

I have a struct that contains a declaration like this one:

No you don't. That's a syntax error. You're looking for:

void (*functions[256])();

Which is an array of function pointers. Note, however, that void func() isn't a "function that takes no arguments and returns nothing." It is a function that takes unspecified numbers or types of arguments and returns nothing. If you want "no arguments" you need this:

void (*functions[256])(void);

In C++, void func() does mean "takes no arguments," which causes some confusion (especially since the functionality C specifies for void func() is of dubious value.)

Either way, you should typedef your function pointer. It'll make the code infinitely easier to understand, and you'll only have one chance (at the typedef) to get the syntax wrong:

typedef void (*func_type)(void);
// ...
func_type functions[256];

Anyway, you can't assign to an array, but you can initialize an array and copy the data:

static func_type functions[256] = { /* initializer */ };
memcpy(mystruct.functions, functions, sizeof(functions));
Simson
  • 3,373
  • 2
  • 24
  • 38
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
  • Just note that the memcpy() is dangerous and non-portable, as a struct may contain any number of padding bytes. If you use memcpy() like shown here, you must verify that the compiler has no padding enabled. Typically through `assert(sizeof(the_struct.functions) == sizeof(functions))` or similar. – Lundin Mar 15 '11 at 10:33
  • 6
    That's incorrect. `sizeof(some_struct)` returns the size of the structure + any necessary padding. See [this question](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) for example. The usage of `memcpy` above is correct. – Mat Mar 15 '11 at 10:43
  • 4
    ..and in this case, the `memcpy()` isn't being used on structs anyway - it's being used to copy from one array to another, of identical size, which is fine. The fact that the destination array is a struct member is immaterial. – caf Mar 15 '11 at 12:27
  • I probably should have noted that `struct` is a keyword, so using it as a variable name is wrong even for sample code that's never going to come near a compiler. – Chris Lutz Mar 16 '11 at 00:06
  • the difference between `func()` and `func(void)` is just a matter of `C++` not of C, is it? – dhein Jan 21 '16 at 07:48
16

I had the same problem, this is my small program to test the solution. It looks pretty straightforward so I thought I'd share it for future visitors.

#include <stdio.h>

int add(int a, int b) {
    return a+b;
}

int minus(int a, int b) {
    return a-b;
}

int multiply(int a, int b) {
    return a*b;
}

typedef int (*f)(int, int);                 //declare typdef

f func[3] = {&add, &minus, &multiply};      //make array func of type f,
                                            //the pointer to a function
int main() {
    int i;
    for (i = 0; i < 3; ++i) printf("%d\n", func[i](5, 4));
    return 0;
}
Swedgin
  • 815
  • 1
  • 11
  • 20
3

You can do it dynamically... Here is a small example of a dynamic function array allocated with malloc...

#include <stdio.h>
#include <stdlib.h>

typedef void (*FOO_FUNC)(int x);

void a(int x)
{
    printf("Function a: %d\n", x);
}

void b(int x)
{
    printf("Function b: %d\n", x);
}

int main(int argc, char **argv)
{
    FOO_FUNC *pFoo = (FOO_FUNC *)malloc(sizeof(FOO_FUNC) * 2);
    pFoo[0] = &a;
    pFoo[1] = &b;

    pFoo[0](10);
    pFoo[1](20);

    return 0;
}
Artyer
  • 31,034
  • 3
  • 47
  • 75
TurtleToes
  • 2,047
  • 2
  • 17
  • 17
  • My bad... wrong context to this discussion... Instead, you could use typedef to define FOO_FUNC type, and then create a FOO_FUNC array and use the names as initializers... – TurtleToes Mar 15 '11 at 12:43
1

From the top of my head and untested.

// create array of pointers to functions
void (*functions[256])(void) = {&function0, &function1, &function2, ..., };

// copy pointers to struct
int i;
for (i = 0; i < 256; i++) struct.functions[i] = functions[i];

EDIT: Corrected syntax error as said by Chris Lutz.

orlp
  • 112,504
  • 36
  • 218
  • 315
0

You could do that while declaring your struct instance:

function_structur fs = { struct_field1,
                         struct_field2,
                         {function0, function1, ..., function255},
                         struct_field3,
                         ... };

You cannot use this shortcut for initialize arrays after the array has been declared: if you need to do that, you'll have to do it dynamically (using a loop, a memcpy or something else).

peoro
  • 25,562
  • 20
  • 98
  • 150
0

If you want to post-initialize an array using form like {func1, func2, ...}, this can be accomplished in the following way (using GCC):

UPD (thanks to Chris Lutz for remarks)

Define a macro like this:

#define FUNCTION_VECTOR_COPY(destVec, sourceVec) memcpy(destVec, sourceVec, sizeof(sourceVec))

And pass source vector using Compound Literals, as follow:

#include <string.h>
...
void (*functions[256])();
...
FUNCTION_VECTOR_COPY (functions, ((void(*[])()) {func1, func2, func3}));
syntagma
  • 23,346
  • 16
  • 78
  • 134
Martin Babacaev
  • 6,240
  • 2
  • 19
  • 34
  • 1
    `sizeof(funcsFrom)` is invalid here. Arrays in function parameters decay to pointers so your function is really `void setFuncs(void(**funcsTo)(), void(**funcsFrom)())` with no information about the `sizeof`. You should a) use a macro, which would allow you to do that, or b) pass the array size as a third parameter. And if you do b, you can even c) write a wrapper macro that automatically plugs in the third argument based on the `sizeof` the second. Furthermore, d) use `sizeof(funcsFrom) / sizeof(funcsFrom[0])` in case the types change, and e) your function is otherwise identical to `memcpy`. – Chris Lutz Mar 16 '11 at 00:11
  • @Chris thanks for the vital remarks, I've tested for 2 values only, that why I missed `sizeof` issue. (a) - great!; (d) - ok, but you should check first if source vector has size greater than 0; (e) - yep, but you should not forget to include `string.h`. See updated answer. – Martin Babacaev Mar 16 '11 at 10:20