2

I have a function defined in a header-only library that looks like this:

inline bar **foo_ptr() {
    static bar *value = NULL;
    return &value;
}

This is my hackish way of initializing a global variable without defining it in a *.c file.

This compiles fine in VS2010 (after a #define inline __inline), but dies in an angry fit of multiple definition rage upon any attempt to compile it in MinGW. This is making me Very Sad.

AFAIK, I can't just use a static inline function, as it would create multiple occurrences of value, which, for this situation, is a Very Bad Thing.

What keyword(s) should I really be using in order to make this work? Am I going at it completely wrong? Is there an alternative way to initialize a header-only global variable to NULL?

I would prefer to stay away from init methods.

Thanks :D

YellPika
  • 2,872
  • 2
  • 28
  • 31
  • 2
    _Why_ do you need a header-only global variable? Does your workplace have some corporate standard limiting the number of C files you're allowed to use? :-) – paxdiablo Feb 14 '12 at 03:46
  • 2
    Why not just use a global variable? That's essentially what you're doing, just in a really obfuscated way. – Jason Coco Feb 14 '12 at 03:48
  • @paxdiablo: Yes. I'm working on a Very Small Library, and it seems like such a waste to make the user compile an extra c file _just_ for one variable. In that sense, my workplace (My House) has a corporate (My House Inc.) standard (the My House Standard) for this project limiting the number of C files to zero. :D – YellPika Feb 14 '12 at 04:01
  • @JasonCoco: Global variable in header = angry fit of multiple definition rage. So no :D – YellPika Feb 14 '12 at 04:01
  • 2
    @YellPika That's only if you initialize it. That's to let the compiler help warn you that you're using the same global variable in multiple implementation files without doing the extern thing. Since you don't want to do the extern thing, just declare the variable without initializing it. THe compiler will not throw a fit and the compiler will initialize it to NULL during compilation. – Jason Coco Feb 14 '12 at 04:03
  • 1
    @YellPika That said... there's probably a much better way to do what you're trying to do... like declare, initialize and control access to the variable through functions in the implementation file that makes most sense and declare an extern in your global header file or the access functions. – Jason Coco Feb 14 '12 at 04:05
  • @JasonCoco I thought that the variable would be initialized to something utterly random (or whatever happened to be left in that memory chunk last). – YellPika Feb 14 '12 at 04:11
  • 1
    @YellPika No, it is required to be initialized to 0 by the C spec (can't remember if that's new in C99 or if it's old tho). It's stack variables that are garbage when they're declared simply by the nature of how the stack works. – Jason Coco Feb 14 '12 at 04:13
  • Oh wait - I stand corrected. You just solved my problem. Too bad comments can't be marked as answers XD. +1 for your comment. – YellPika Feb 14 '12 at 04:15
  • If you're really intent on not defining a global variable in a `.c` file, you could potentially define it instead in a [linker script](http://www.delorie.com/gnu/docs/binutils/ld_6.html), but that seems like a lot of wasted effort. Just define it in a `.c` file that gets compiled once. – Adam Rosenfield Feb 14 '12 at 04:28
  • @JasonCoco: Note that the C standard requires one definition of the variable. It notes the common extension that allows multiple tentative definitions, and as long as at most one of those is initialized, on those systems that support the common extension, you will be OK. But that is not strictly standard conforming. (See Appendix J in the C99 standard: §J.5.11 Multiple External Definitions to be precise.) – Jonathan Leffler Apr 29 '12 at 21:46

2 Answers2

1

The C99 standard says in section §6.7.4 Function specifiers:

¶2 An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static storage duration, and shall not contain a reference to an identifier with internal linkage.

Your function is currently trying to return a pointer to a local variable; that is a well-known no-no. But the standard prohibits you from changing that variable into a static. If there was an external variable value, then it could be made to work, sort of. But it probably defeats the objective you were trying to achieve:

extern bar *value;

inline bar **foo_ptr() {
    value = NULL;
    return &value;
}

But the variable must be declared, so it is accessible. It must also be defined somewhere. Frankly, you'll be better off just accepting that if you need a global variable, it is best to use (declare, define) one.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
-1

Well, I'm gonna answer my own question here, but credit all goes to Jason Coco (if you feel like making your own answer I'll gladly accept that instead).

Anyways - the solution was to simply declare the global variable without initializing it. The compiler would automatically set it to null.

bar *foo;

Problem solved :)

YellPika
  • 2,872
  • 2
  • 28
  • 31
  • 1
    Note that the C standard requires one definition of the variable. It notes the common extension that allows multiple tentative definitions, and as long as at most one of those is initialized, on those systems that support the common extension, you will be OK. But that is not strictly standard conforming. (See Appendix J in the C99 standard: §J.5.11 Multiple External Definitions to be precise.) As long as you know that you are using an extension that is not universally supported, that's fine. – Jonathan Leffler Apr 29 '12 at 21:48
  • Also explained here: https://stackoverflow.com/a/55404584/2284995 – zwhconst Feb 19 '22 at 04:52