0

I have essentially this:

void **a;

typedef void (*ExampleFn)();

void
foo() {
  puts("hello");
}

void
init() {
  ExampleFn b[100] = {
    foo
  };

  a = malloc(sizeof(void) * 10000);

  a[0] = b;
}

int
main() {
  init();

  ExampleFn x = a[0][0];
  x();
}

But when running I get all kinds of various errors, such as this:

error: subscript of pointer to function type 'void ()'

How do I get this to work?

Doing something like ((ExampleFn*)a[0])[0](); gives a segmentation fault.

Lance
  • 75,200
  • 93
  • 289
  • 503
  • Assigning something that is not a function to a function pointers is invalid. Doing `sizeof(void)` is also invalid. Apart from that, what you want is `sizeof(void*)` and `x = a[0]`. – Marco Bonelli Apr 12 '20 at 02:16
  • One True Brace but with the return type on a separate line ... never seen that – M.M Apr 12 '20 at 02:16
  • `**a` is not a pointer to a void function, it's just a void. So `a[0]` has type `void`, and `a[0][0]` is an attempt to dereference a void pointer, which doesn't make sense. Then it tries to assign a void value to `x`, which is an error (what would it even mean?) – Tom Karzes Apr 12 '20 at 02:16
  • 1
    `a[0] = b;` can't work in any case, as `b` is a function pointer whereas `void *` can only store object pointers – M.M Apr 12 '20 at 02:17
  • How can I accomplish what I'm theoretically trying to accomplish, given I am way off then? I ripped this out of a large project so it might not be 100% accurate. But it's close to what I'm trying to do. – Lance Apr 12 '20 at 02:17
  • @MarcoBonelli See M.M's comment. You can't store a function pointer in a `void *` (try specifying `--pedantic` with gcc and it will tell you). – Tom Karzes Apr 12 '20 at 02:20
  • If the setup is incorrect, how should it be setup to accomplish what I'm doing, given I want the "nested array". – Lance Apr 12 '20 at 02:21
  • Another problem with this code is that it uses incomplete function prototypes. For historical reasons, declaring a function `void init()` does *not* mean that `init` takes no arguments. It means that the argument types are unspecified. The proper way to declare it to have no arguments is `void init(void)`. That is a complete function prototype that indicates the function takes no arguments. – Tom Karzes Apr 12 '20 at 02:57
  • A more serious problem is this: `a[0] = b;` in function `init`. `b` is a local variable with automatic storage, which means it is no longer available after `init` returns. So `a` will contain a pointer to undefined storage. – Tom Karzes Apr 12 '20 at 03:12

1 Answers1

0

It seems like you're trying to make an array of function pointers. The code could look like this (partial code):

ExampleFn *a;

void init()
{
    a = malloc(100 * sizeof *a);
    a[0] = foo;
}

int main()
{
    init();
    ExampleFn x = a[0];
    x();
}

In Standard C, the void * type is only for pointers to object type, not pointers to function.

You can make a 2-D or 3-D jagged array in the same way as you would for object types (e.g. see here), just use ExampleFn instead of int as in that example.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Is there any way to have _nested_ function pointers? That's what I'm trying to get at. – Lance Apr 12 '20 at 02:21
  • @LancePollard I don't know what you mean by "nested function pointers" – M.M Apr 12 '20 at 02:22
  • So I can do `a[0][0]()` or if it was `void **a = malloc(); void **b = malloc(); void **c = malloc(); a[0] = b; b[0] = c; c[0] = arrayOfFunctions`, etc. How can I do something like that? `a[0][0][0][0]()`. – Lance Apr 12 '20 at 02:23
  • @LancePollard you seem to be describing a 3-D array – M.M Apr 12 '20 at 02:24
  • Put another way, I want a jump table, but I want to assign the jump table to a struct property that is a void** or void* type. – Lance Apr 12 '20 at 02:27
  • 1
    @LancePollard I added a link to multi-dimensional array example – M.M Apr 12 '20 at 02:28
  • `error: initializing 'ExampleFn **' (aka 'void (***)()') with an expression of incompatible type 'void'; ExampleFn **x = a[0][0];` – Lance Apr 12 '20 at 02:29
  • @LancePollard `ExampleFn x = a[0][0];` (if you have made `a` be `ExampleFn **a;` and the appropriate mallocs) – M.M Apr 12 '20 at 02:31
  • Better to declare `void init(void)` rather than to leave the argument types unspecified. – Tom Karzes Apr 12 '20 at 02:37
  • @TomKarzes that depends on the intended usage – M.M Apr 12 '20 at 02:38
  • @M.M This is a concrete case. `init` is not a variadic function. It takes no arguments. The proper prototype should list `void` for the arguments. – Tom Karzes Apr 12 '20 at 02:41
  • @TomKarzes the question is very vague but I get the impression that it will be intended to store multiple function pointers in the table and we have not been told anything about the argument types of those the other functions – M.M Apr 12 '20 at 02:42
  • @M.M Yes, but that should have no effect on the declaration of `init`. That should only affect the type of `ExampleFn`. `init` should declare its arguments correctly, just as it would if it actually had any. If it took an `int` argument, you wouldn't suggest leaving that out of the prototype, right? This case is no different. – Tom Karzes Apr 12 '20 at 02:44
  • @TomKarzes oh, I thought you were referring to the functions in the table . Never mind – M.M Apr 12 '20 at 02:46
  • @M.M No, I'm objecting to the old, K&R style declaration of the `init` function. As I said in my first comment, it should be declared `void init(void)`. The same applies to `foo`. People should not be using K&R declarations this many decades after ANSI C introduced function prototypes. – Tom Karzes Apr 12 '20 at 02:48