2

I just need a way to restrict access of a global variable per my functions in C not C++

static int global_int = 10;

int main(void)
{
   global_int = 20;    // allowed
}

void f()
{
   global_int = 30;   // global_int cannot be used here
}

What does I mean is, having more functions in a translation unit, I need to prevent some functions to access the global variable and allow some other function; instead of defining this variable in each function uses this variable.

mada
  • 1,646
  • 1
  • 15
  • 1
    It can't be done if the functions are all in the same file. One solution is to move `f` to a seperate source file. Or more hacky is to move the variable definition to re-arrange the file such that the variable definition occurs after functions that shouldn't access it - that's not very reliable so wouldn't recommend it. – kaylum Sep 22 '21 at 07:15
  • `void f() { int global_int = -42; /*hide real global*/ }` ... BTW is it `global_var` or `global_int`? – pmg Sep 22 '21 at 07:19
  • 1
    @pmg, it's even better to use const `void f() { const int global_int = -42; `. It will make error whenever the variable is written to. – tstanisl Sep 22 '21 at 08:24
  • does the access mean just preventing to writing to the global variable? Ot preventing both reading and writing? – tstanisl Sep 22 '21 at 08:38
  • 1
    @tstanisl. means both reading and writing – mada Sep 22 '21 at 08:51

5 Answers5

2

What you try to do is not possible. Instead, define those functions that are allowed to access the static global variable into a separate translation unit and define all the other functions in other translation unit(s).

So move f into a separate file and keep main in the same place as the definition of global.

There are other ways to hide informations in C, but in all cases it's just a convention that you establish for yourself and it's supposed you know what you are doing (this is the philosophy of C).

alinsoar
  • 15,386
  • 4
  • 57
  • 74
2

"static" (internal linkage) and "global" (external linkage) are mutually exclusive. You cannot have a "static global". You can however declare static variables at file scope - that is, outside any function body. Such variables then get internal linkage and static storage duration.

A static variable declared at file scope is accessible by every function residing in the same translation unit. Simply put: by any function present in the same .c file as the variable.

The correct solution is therefore to place main in the same .c file as the variable and the function f in a different .c file.

Example: Suppose you are designing a module called "stuff". stuff.h is then your public interface, stuff.c could contain the private implementation of some functions from the header and yet another file stuff_internal.c could contain other function definitions. Both stuff.c and stuff_internal.c include stuff.h but the static file scope variable and all functions using it are placed in stuff_internal.c.

For more advanced ways of achieving private encapsulation with multiple instances of an object in a thread-safe manner, see How to do private encapsulation in C?

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

static and extern are separate qualifiers. static is only visible within the scope of the file. You can define main() and f() in separate files. You can define global_int as static in both files, they will be separate variables for the compiler.

static variables are allocated memory in data segment, not stack segment. If you want the variable to be visible across all files, declare them as extern.

moi
  • 467
  • 4
  • 19
0

This problem is a symptom of the bad design, the correct approach is described in the other answers. However, it your options are limited you can use a following hack.

The problem can be addressed with preprocessor. Just add a global_int macro that expands to itself.

#define global_int global_int

There will no recursion because the expanded macro is always disabled the it is applied.

The when entering the "forbidded zone" just undefine this macro. optionally replace it with something else like global_int__guard to get better diagnostics. And replace it back when leaving the forbidded zone.

#undef global_int
#define global_int global_int__guard

... code with no access to `global_int`

#undef global_int
#define global_int global_int

Any access toglobal_int will cause a compilation error that global_int__guard is undeclared.

You could use push/pop macro pragmas if your compiler supports it to make this process a bit more convenient.

tstanisl
  • 13,520
  • 2
  • 25
  • 40
0

Your options include:

  • Rewrite your program so you do not need such kludges. External variables should mostly be avoided.
  • Rearrange your routines so the ones that should not see the variable are earlier:
void f(void)
{
    // global_int is not visible here.
}

static int global_int = 10;

int main(void)
{
    global_int = 20;
}
  • If the variable is used only inside one function, declare it only inside that function:
int main(void)
{
    static int global_int = 10;
    global_int = 20;
}

void f(void)
{
    // global_int is not visible here.
}
  • Use macros as in tstanisl’s answer to conceal the name in some places.
  • Split your functions across translation units according to the variables they should see.
  • Hide variables by declaring the same name in an incompatible way in a new scope:
static int global_int = 10;

void f(void)
{
    typedef struct foo global_int;
    …
    global_int = 20; // Gets an error because global_int is a type, not a variable.
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312