10

Let’s say I only want to expose a function from one of my files by passing out a function pointer to that function. Is it safe to declare that function as static? Are compilers allowed to do any judo that would invalidate my function pointer, or make it meaningless outside the context of that file, since the function is declared as specific to that file?

Not my code, but a (silly) example of what I mean:

void    static   cool_function(void);
void    extern (*cool_function_ptr)(void); // Actually, I’m not sure of where the `extern` goes in a function-
                                           // pointer declaration. Damn you, confusing function-pointer syntax!

Given that code (or the syntactically correct approximation thereof), would it be illegal to access cool_function_ptr from another file?

ELLIOTTCABLE
  • 17,185
  • 12
  • 62
  • 78
  • 1
    All very good answers. Sometimes Stack Overflow surpasses my expectations! :D – ELLIOTTCABLE Feb 28 '11 at 05:04
  • You can make that always. You will be amazed on different dimensions of answers that comes out when you ask it on SO. – Shamim Hafiz - MSFT Feb 28 '11 at 05:23
  • I usually get quite a lot of irrelevancy, as well as not-well-thought-out answers that somebody sniped in just to be one of the first responses on a new question, and thus be almost guaranteed an upvote (or even accept.) It’s rare that every single answer is relevant, much less every single answer being *useful*! – ELLIOTTCABLE Feb 28 '11 at 05:42

5 Answers5

11

It is completely safe to do so, and often useful. The same goes for static variables and data pointers. If the compiler wants to do any fancy optimizations (like nonstandard calling conventions, inlining, refactoring, etc.) that could interfere with the ability to call the function through a function pointer from a different translation unit, it's the compiler's responsibility to either determine that the address of the function is never taken, or to generate multiple versions of the code, one of which is safe to be called from outside with the standard calling convention.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • This is exactly what I wanted to know. Any chance you have a few relevant links to the spec? I trust you word on it, though. Just curious, always want to learn more. – ELLIOTTCABLE Feb 28 '11 at 05:03
  • 1
    The relevant part of the spec is simply the text about function pointers, and *the lack* of any statement forbidding using pointers to functions with static linkage. – R.. GitHub STOP HELPING ICE Feb 28 '11 at 05:07
  • 3
    This is used all the time, such as when filling in structs of function pointers representing a common API implemented by multiple modules (e.g.: filesystems in a kernel). – Conrad Meyer Feb 28 '11 at 05:09
3

Sure. A function pointer is just an address, there's nothing magical about it.

Here's an example:

$ cat Makefile
.PHONY: all
all:    main
        ./main
main:   main.c other.c 
        gcc -o main main.c other.c 
$ cat main.c
#include <stdio.h>

static void goodnight(){
  printf("Goonight, gracie!\n");
  return;
}

int
main(char * argv[], int argc){
  other(goodnight);
  return 0;
}
$ cat other.c
#include <stdio.h>

void other(void(*fp)()){
  fp();
  return ;
}
$ make
gcc -o main main.c other.c 
./main
Goonight, gracie!
$ 

The hard part is getting the declaration of a function taking a pointer to function returning void right.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • See my discussion with [Aredridel](http://stackoverflow.com/users/306320/aredridel) below; I’m not worried about getting an address, I’m worried about whether an optimizing compiler can trash said address. Make sense? – ELLIOTTCABLE Feb 28 '11 at 05:02
  • Yes, and the answer is "no". In fact, it might very well thwart other optimizations, since it can't (for example) identify inline-able code, since the compiler doesn't know *which* code will be there. – Charlie Martin Feb 28 '11 at 05:24
1

The only thing that might bite you is if the function is inlined -- and taking the address of it for a pointer should keep that from happening.

Doing this kinda keeps the caller from knowing the full signature, so you're playing with fire and hoping things line up though.

And it's "extern void" and "static void" -- storage class, then return type.

aredridel
  • 1,532
  • 14
  • 19
  • That’s what I’m worried about. Not whether the compiler will allow it, but whether it’s *legal* for optimizations to subsequently trash my pointer. Got relevant links to the specification, by any chance? (Also, aren’t the storage class and type interchangeable?) – ELLIOTTCABLE Feb 28 '11 at 05:00
  • Also, what do you mean, by “keeps the caller from knowing the full signature?” The signature would still be in the header; the API consumer would simply be forced to call the function through the pointer instead of directly, yes? – ELLIOTTCABLE Feb 28 '11 at 05:01
  • That would depend on how the caller gets the pointer. If you're declaring it static in the header, then the caller gets its own copy and the compiler carps about not having it implemented in that unit. The signature then matches but at the cost of having confused things. You could typedef it though, and make it a pointer of that type. – aredridel Feb 28 '11 at 05:15
  • And optimizations should never trash valid code like that. Taking the address of a function is legal unless you specifically say "this function is really special and __implspecific__ __inline__ __foo__". – aredridel Feb 28 '11 at 05:16
  • Thanks for the info. And I’m wondering who voted you down, because you’re back to 0 on this post and 19 overall. o_O – ELLIOTTCABLE Feb 28 '11 at 05:52
1

There's nothing different about a pointer to a static function.

However, passing the pointer around may be slightly less efficient than allowing it to be called directly. It wasn't entirely clear to me why you're doing that, but it didn't make much sense to me.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
1

Definitely allowed, potentially perfectly reasonable


The language allows you to pass a pointer to a static function outside of a module.

Therefore, any tricks that the compiler might do in compiling intra-module calls must somehow be compatible with what you are doing.

In general, I would say it's actually a good code pattern, relative to making the function global, because you are additionally encapsulating the function, although one could make the opposite argument with respect to a simple static function with no external references.

All-in-all, I think it's the design of your objects and your application that matters, and not whether you globally reference a static function.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329