0

I was playing around with function pointers, and ran into something that intuitively doesn't fit with my understanding of pointers in C.

Take a look at the following code:

include <stdio.h>

void fun(int a) {
    printf("fun, %d!\n", a);

}

void bun(int b) {
    printf("bun, %d!\n", b);
}


int main(){

    void (*fooptr)(int) = &bun;
    void (*blooptr) (int) = fun;

    fooptr(200);
    blooptr(100);

    return 0;
}

If I treated function pointers like any other pointer in C, I should expect void (*blooptr) (int) = fun; to trigger a compiler warning against incompatible types. My code compiles (silently) and works as expected.

How does C let me initialize a function pointer without the & operator, like I would do a regular pointer, without even a compiler warning? Is this one of those cases where I'm accidentally getting the right behaviour, though I'm technically in undefined behaviour territory? If someone could explain why this works, with some insight (references to literature will also do) into the nature of function pointers, that would be great.

I tried looking around for this specific question, but couldn't find anything related. Seems a bit fundamental, so apologies if it's a dup.

aspen100
  • 965
  • 11
  • 22
  • It's like passing arrays - C reserves the right to be inconsistent, confusing and only require an address operator 'sometimes' :( – Martin James Dec 07 '17 at 07:51

1 Answers1

0

Function type in C automatically and implicitly decays to function pointer type (as if unary & operator was quiety applied). This decay takes place in all contexts, with the exception of unary & operator and sizeof operator. For this reason

void (*fooptr)(int) = &bun;

and

void (*fooptr)(int) = bun;

are two alternative ways to say the same thing.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Could you expand on this part? "This decay takes place in all contexts besides unary & operator and sizeof operator" – aspen100 Dec 07 '17 at 01:49
  • @aspen100: It means that expression `bun` is quietly interpreted as `(void (*)(int)) bun` everywhere, except when you do `&bun` (it is NOT interpreted as `&(void (*)(int)) bun`) and except when you do `sizeof bun` (it is NOT interpreted as `sizeof (void (*)(int)) bun`, it is interpreted as invalid application of `sizeof` instead). In all other contexts `bun` is equivalent to `(void (*)(int)) bun`, which is the same as `&bun`. – AnT stands with Russia Dec 07 '17 at 01:53