Live data from Hacker News

How Do I Declare a Function Pointer in C?

fuckingfunctionpointers.com

101–110 of 111 posts

Re: How Do I Declare a Function Pointer in C?

#101
post #93

Earlier quoted context omitted.

Last time I checked, Clang doesn't support nested functions although it supports most of GNU extensions (or similar features with slightly altered syntax). I'm not 100% sure what you mean by "proper closure" but it does capture variables from the outer scope. It has limitations with scopes and lifetimes, of course.

Proper closures require "fat pointers", basically you're storing two pointers, one to the function and one to its context data. (In the case of a nested function that's its stackframe.) They also require that stackframes be generally allocated on the heap. C doesn't have a type for that, it only has function pointers, which only have space for a single pointer. So what GCC does is actually a horrible hack - it dynami…

Yes, it's a bit ugly but it still doesn't make it useless. It could be useful for e.g. passing a comparator to qsort using a captured variable to pass the comparison criteria (e.g. compare arrays according to the n'th element).

> So what GCC does is actually a horrible hack - it dynamically creates a function (called a trampoline), which calls the actual function with a pointer to its data.

Well you can call it a horrible hack but it's pretty clever. There's no other way to do this without having a rich runtime system and a language with a built-in concept of a heap (and perhaps a garbage collector).

> And since the trampoline is also allocated on the stack, this requires the stack to be executable, which is Not Great for security.

Yeah - this is pretty nasty. Executable stack is less than useful, although it's not enough to protect against stack/buffer overflow exploits that utilize ROP or other advanced attack methods.

However - in my practical experiments, I have noticed that the optimizer will get rid of most trivial trampolines if the resulting function pointer isn't stored or passed to a function in a foreign translation unit. LLVM in particular is really good in eliminating trampolines.

I wish there was a way to have compile time certainty that no trampolines ever get emitted on the stack. You could still use capturing nested functions with certain limitations.

But yeah - it's not the most useful feature, primarily because it's GCC only and secondarily because, at worst, you'll end up executing a few bytes of machine code from the stack.

Re: How Do I Declare a Function Pointer in C?

#102

The easiest and best way to learn the syntax is to not memorise specific cases but the grammar itself, which IMHO is no more difficult than the existing concept of operator precedence. Everyone using C should hopefully already know that multiplication has higher precedence than addition, so likewise function call (and array subscripting) has higher precedence than pointer dereference. Thus this table should make it c…

Stackoverflow related question/answer: http://stackoverflow.com/a/34548829/1119701

Re: How Do I Declare a Function Pointer in C?

#103
post #15

Just use the typedef. Even if you personally find the other variants readable, chances are that your peer reading your code doesn't.

Personally I don't like when people hide a pointer behind a typedef. If you want to use a typedef, typedef the function and then declare a pointer to that: typedef int func(void); func *func_ptr; Avoids the mess of the function pointer syntax, but still makes the fact that it is a pointer clear.

+1. This is exactly how I do it, because it's the only sane way I could maintain (even my own) code :)

Re: How Do I Declare a Function Pointer in C?

#104

I never got used to having variables sandwiched inside a type. I know I am not supposed to suggest out-of-the-box, but why can't we add a new syntax, e.g.: return_type Fn(parameters) var; typedef return_type Fn(parameters) TypeName; where Fn is a new keyword -- or not, if compiler understands dummy syntax -- (I would suggest λ when using greek letters in code become norm). It simplifies the C syntax a lot IMHO…

Another thorn in the C syntax is to allow a single statement following if, for, while, etc.. How many pitfalls, walk-around have we struggled with because of it? Just put the braces into the statement syntax please.

Re: How Do I Declare a Function Pointer in C?

#105

The easiest and best way to learn the syntax is to not memorise specific cases but the grammar itself, which IMHO is no more difficult than the existing concept of operator precedence. Everyone using C should hopefully already know that multiplication has higher precedence than addition, so likewise function call (and array subscripting) has higher precedence than pointer dereference. Thus this table should make it c…

What we need realize is that simple grammar does not always lead to simple comprehension. Nesting the grammar elements more than a few levels is always difficult for our current biology equipment.

Re: How Do I Declare a Function Pointer in C?

#106

Earlier quoted context omitted.

In C++, pointers to member functions are even more cumbersome than C function pointers.

auto greet = std::mem_fn(&Foo::display_greeting); Looks pretty simple to me, much simpler than C function pointers. :) Pairs nicely with std::bind, too, like so: Foo foo; std::function setter = std::bind(&Foo::setValue, &foo, std::placeholders::_1); setter(42);

Indeed, C++ is an excellent language, extremely writable; but readable, it isn't.

Re: How Do I Declare a Function Pointer in C?

#107
post #15

Just use the typedef. Even if you personally find the other variants readable, chances are that your peer reading your code doesn't.

No don't use typedefs there's no real reason[1] and it may cause problems. Also if your peer can't read a function pointer I don't know what help you plan on getting from them anyway, chances are you are helping/teaching them, not the other way around. [1]: http://yarchive.net/comp/linux/typedefs.html

Linus directly contradicts you in that linked thread, for this specific situation:

  And as mentioned, there _are_ exceptions. Some types just get _sooo_
  complex that it's inconvenient to type them out, even if they are
  perfectly regular types, and don't depend on any config option. The
  "filldir_t" typedef in fs.h is such an example - it's not really opaque,
  _nor_ is it a config option, but it sure as hell would be inconvenient for
  all low-level filesystems to do
  
    int my_readdir(struct file *filp, void *dirent,
        int (*filldir)(void *, const char *, int, loff_t,
        u64, unsigned))
    {
        ...
    }
  
  because let's face it, having to write out that "filldir" type just made
  me use two lines (and potential for totally unnecessary tupos) because the
  thing was so complex. So at that point, using a typedef is just common
  sense, and we can do
  
  	int my_readdir(struct file *filp, void *dirent, filldir_t filldir)
  	{
  		...
  	}
  
  instead.
  
  But it's really quite hard to make that kind of complex type in C. It's
  almost always a function pointer that takes complex arguments.

Re: How Do I Declare a Function Pointer in C?

#108

The easiest and best way to learn the syntax is to not memorise specific cases but the grammar itself, which IMHO is no more difficult than the existing concept of operator precedence. Everyone using C should hopefully already know that multiplication has higher precedence than addition, so likewise function call (and array subscripting) has higher precedence than pointer dereference. Thus this table should make it c…

You define a variable the same way you would use it.

    int *a             -> expression *a has type int.
    int *a[10]         -> *a[_] has type int.
    int (*a)[10]       -> (*a)[_] has type int.
    int (*a)(int, int) -> (*a)(_, _) has type int.
No need for complicated things like "spiral rules", etc.

Re: How Do I Declare a Function Pointer in C?

#109

Earlier quoted context omitted.

Correct me if I'm wrong, but isn't a "function" always a pointer in C? That is, there's no such thing as a "value function" in C, right? Given that, what's the advantage for "your version" of the idiom? (This may just be nitpicking.)

This is very similar to the 'array-type', which I've written about before (And could talk about if you're interested). Functions (and arrays) degrade into a pointer to themselves when used in most situations (for functions, I can't think of a real case where it doesn't degrade, besides declarations). But the 'func' in this case is the type of a 'function' ('value function' as you're referring). Interestingly, declari…

The main case where a function does not decay into a pointer is in a function call :-)

BUT since ANSI C you can call a function pointer directly: you no longer have to write (*fptr)(arg).

So there is automatic invisible conversion in both directions.

Re: How Do I Declare a Function Pointer in C?

#110
post #83

Earlier quoted context omitted.

What they were thinking can be see in K&R C - there is no "typedef" in early C. Without typedef, the syntax of C is context-independent and LALR-1. You don't have to know if a name is a type to parse the syntax. Then came "typedef", which broke parsing. C parsing became context-dependent. To parse C with "typedef", and especially C++, you must read all the header files first. With name-first declaration syntax (Pasca…

That's interesting -- I was wondering in which cases typedef changes the parse tree, and came across a few [1]: a (b); /* function call or declaration */ a * b; /* multiplication or declaration */ f((a) * b); /* multiplication or deref and cast */ > With one further change, namely deleting the production typedef-name: identifier and making typedef-name a terminal symbol, this grammar is acceptable to the YACC parser-…

С++ takes it all the way to 11 with templates. Here's a program that is parsed differently depending on whether pointers are 32-bit or 64-bit:

    template struct a;

    template struct a {
        enum { b };
    };

    template struct a {
        template struct b {};
    };

    enum { c, d };

    int main() {
        a::bd;
        d;
    }
Depending on which instantiation is used, the first line of main is either a variable declaration, or two operators applied in sequence.

This is especially fun to deal with for C++ IDEs that support semantic highlighting (i.e. typenames are in a different color etc). If I remember correctly, the first one that could handle this right was VS 2012 - it only took 14 years after ISO C++ standard was released...

Post reply on HN