views:

454

answers:

4

Is there any way to keep global variables visible only from inside a library while inaccessible from programs that access that library in C?

It's not that it is vital to keep the variable protected, but I would rather it if programs couldn't import it as it is nothing of their business.

I don't care about solutions involving macros.

+8  A: 

If you use g++, you can use the linker facilities for that using attributes.

__attribute__((visibility("hidden"))) int whatever;

You can also mark everything as hidden and mark explicitly what is visible with this flag: -fvisibility=hidden

And then mark the visible variables with:

__attribute__((visibility("default"))) int whatever;
Arkaitz Jimenez
Does that work with GCC as opposed to G++? And, in C++, wouldn't you use a library-specific namespace such as "namespace LibName::Private { ... } " to hold the library's private variables. (And the partial answer to my question is that GCC on MacOS X says -fvisibility is language independent.)
Jonathan Leffler
Yes, it will work with gcc too as it is language independant, it is used for symbols in the library, so any compiled language should accept that with gcc.Even if you use in c++ the namespace solution, the symbol is still public, you could access it through LibName::Private::hiddenvar from outside.
Arkaitz Jimenez
Note: this is a GCC 4.x feature.
Jonathan Leffler
I'm not sure I understand exactly the functionality of the attribute. Let me restate what you said to better understand. Basically the __attribute__((visibility("hidden"))) lets you have similar functionality of C++ namespaces in C ?
Trevor Boyd Smith
So all the library code would compile with "-fvisibility=hidden" specified to gcc? And all the code using the library would not be able to access any globals specified with __attribute__((visibility("hidden"))) ?
Trevor Boyd Smith
@Trevor: Essentially this is only a feature of some shared library formats. It doesn't affect binaries, object files or static libraries. And yes, hidden symbols will not be visible outside the shared library. Another way to do the same is with symbol versioning.
janneb
Huh, why am I suddenly called "null"? boggle..
janneb
+4  A: 
static int somelocalvar = 0;

that makes somelocalvar visible only from whithin the source file where it is declared (reference and example).

dsm
I know, but the variable must be global across lib modules. cramming everything into a single file or using functions is not an option.
jbcreix
Global variables like that are signs of a design flaw. I would re-think what you are trying to do if I were you.
dsm
I don't think there is any other way. It is that or a function, and the overhead is brutal for functions. This is why I am asking.The behavior of a whole class of functions depend on knowing that value.
jbcreix
Maybe if the variable is really so important you should re-organize the library to take this into consideration
dsm
A: 

You can use another header file for exporting functionality to outside modules than you have for the internal functionality and thus you don't have to declare globals that doesn't have to be accessible from outside the module.

Edit: There is only linker problems if you declare things more than once. There is no need to keep all global data in one header file, in fact, there may be a wise reason top split it up into several smaller pieces for maintainability and different areas of responisiblity. Splitting up into header files for external data and internal data is one such reason and this should not be a problem since it is possible to include more than one header file into the same source file. And don't forget the guards in the header files, this way, collision in linking is mostly avoided.

#ifndef XXX_HEADER_FILE
#define XXX_HEADER_FILE
code
#endif
Tobias Wärre
You'll still get linker collisions though.
Blank Xavier
+2  A: 

Inside the library implementation, declare your variables like that:

struct my_lib_variables
{
  int var1;
  char var2;
};

Now in the header for end-users, declare it like that:

struct my_lib_variables;

It declares the structure as an incomplete type. People who will use the header will be able to create a pointer to the struct, but that's all. The goal is that they have to write something like that:

#include "my_lib.h"

struct my_lib_variables* p = my_lib_init();
my_lib_do_something(p);
my_lib_destroy(p);

The libray code is able to modify the variables, but the library can't do it directly.


Or you can use global variables, but put the extern declarations inside a header which will not be used by the end-user.

Bastien Léonard