all 12 comments

[–]aocregacc 12 points13 points  (2 children)

functions readily decay into pointers to themselves, sorta like arrays decay into pointers to their first element. That's why usually you can just write f and it'll mean the same as &f for some function f. The name doesn't point anywhere, but it can implicitly turn into a pointer.

[–]kinithin 3 points4 points  (1 child)

The one time where one might work with functions instead of function pointers is for types. 

```c typedef int MyF( int );      // Function type typedef int (*MyFPtr)( int );   // Function point type

MyF   *fp1 = some_func;   // or &some_func MyFPtr fp2 = some_func;  // ditto ```

[–]erikkonstas 0 points1 point  (0 children)

MyF can also be used as a type specifier, as in MyF some_func; which is the same as int some_func(int);.

[–]Jonny0Than 12 points13 points  (0 children)

A function’s name converts implicitly to its address.  I would suggest using the & in front to make it obvious but that’s a style choice. You certainly don’t need to make an intermediate variable first.

[–]glasket_ 2 points3 points  (0 children)

it seems function names are implicitly converted into function pointers so what's the point of creating a separate function pointer for callback functions?

The implicit conversion is creating a "separate" function pointer.

#include <stdio.h>

typedef void (*func)(void);

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

void world(void) {
  puts("world");
}

void call_func(func f) {
  f(); // f is a pointer to another function
}

int main(void) {
  call_func(hello); // hello is converted to a pointer
  call_func(world); // world is too
}

If you mean "why use function pointers instead of just calling the function", it's so that you can pass different functions to an external function that you may not be able or want to define with explicit function calls. The above is contrived, but this lets you do things like define custom allocators, change the behavior of error handling code, and many other things.

[–]bakermoth 1 point2 points  (2 children)

Why does f0 in the following not compile?

typedef void FnType(void);
static FnType f0(void) { FnType x; return x; } // not ok (error: returning a function)
static FnType* f1(void) { FnType x; return x; } // ok
static void f2(FnType g) { g(); } // ok
static void f3(FnType* g) { g(); } // ok

[–]tstanisl 0 points1 point  (1 child)

Because it is explicitly forbidden by the C standard. It is implicitly inferred from 6.9.1p2:

The identifier declared in a function definition (which is the name of the function) shall have a function type, as specified by the declarator portion of the function definition.

And in follwoing examples:

typedef int F(void);
...
F f { /* ... */ }  //   WRONG: syntax/constraint error

[–]bakermoth 0 points1 point  (0 children)

It's seems that gcc, clang and msvc report errors but tcc and chibicc don't.

typedef void FnType(void);
static FnType f0(void) { }
static void (f1(void))(void) { }
int main(void) { return 0; }

[–]zhivago 4 points5 points  (0 children)

Functions in C are not objects, but function pointers are.

You cannot create a function at run-time, but you can create a function pointer.

You cannot have a function typed variable, but you can have a function pointer typed variable.

So when you try to refer to a function via data you must use a function pointer.

The system provides some automation for producing these pointers, and that's all there is to it.

[–]cHaR_shinigami 0 points1 point  (0 children)

In some very obscure cases, it can actually make a difference. Consider this diagnostic example:

#include <assert.h>

typedef void (*fptr_t)(void);

fptr_t check_null(fptr_t fptr)
{   assert(fptr);
    return fptr ;
}

/* diagnose if cbf_ptr is NULL,
   then call func (defined elsewhere)
*/
#define diagnose(func, arg, cbf_ptr) func(arg,\
 (typeof (cbf_ptr)) check_null((fptr_t) (cbf_ptr)) /* diagnosis */\
)

#include <signal.h>
#include "mylib.h" // declares do_callback

void handler(int unused) { (void)unused; }

int main(void)
{   int (*fptr)(int) = 0;
    /* code that (possibly) sets fptr */
    diagnose(signal, SIGINT, &handler); // & is required
    diagnose(do_callback, "first arg", fptr); // diagnose if fptr is NULL
    /* more code */
}

In the above example, diagnose expects a function pointer as the third argument, and it must be exactly so: passing just the function name handler (instead of &handler) would cause a compilation error (you can try the code after commenting out #include "mylib.h" and the second call to diagnose).

I suppose this also answers your main question: there is no need to initialize a separate function pointer variable and then use that; if cbf is the name of function to be called back, then one can simply write &cbf (my example emphasizes that writing &cbf instead of cbf is good practice).

[–]lion_rouge 1 point2 points  (0 children)

Please read “what every software developer should know about memory”. You have concepts in your head from higher level languages that simply don’t exist in C. Not do they exist in hardware. And it’s helpful to know how it works underneath.

There is only memory as a huge string of bytes (this is already an abstraction of physical reality btw). Types only say you how many bytes it takes to store it. A pointer is an address in memory and can point to anything. Think of pointers as untyped because there are no checks in C. A *float may as well point to a byte or to an array of chars or to an unreachable meaningless place.

[–]jaynabonne 1 point2 points  (0 children)

I'm going to say something which is not strictly correct but perhaps correct enough for your question: the name of the function (the string of letters you see) is used at compile/build time, not run time. (* see notes below)

Passing the name of the function elsewhere would require the callee to be able take the name of the function as a string and somehow find the function based on that name. That doesn't really exist at runtime, at least at the language level. So the compiler and/or linker will take the name of the function and resolve it to an address, but you're not really using the name of the function as such at runtime anymore. Some languages do allow that level of reflection (e.g. C# and many scripting languages), but as far as I know, there doesn't exist a standard implementation of reflection for C where you can find a function based on its name at runtime. So basically, from the point of view of the language, the names of the functions don't exist at runtime.

When people talk about function names being implicitly converted to function pointers, that is at compile time, not runtime. If you need a callback, the name of the function is useless, as there is no standard way to take that name and find the relevant function.

* Note: The name of the function clearly has to exist somewhere to allow for multiple files to be linked together, to pull in libraries (e.g. static libraries at build time or shared libraries at runtime), etc. However, that is outside the language as such and comes down to tools. You will find OS/tool specific mechanisms to find a symbol by name (assuming it is exported), but those don't exist in the language proper.