2

There are three files - mainfile.c, helper.c and helper.h. in the same directory. helper.h contains function prototypes of foo1 and foo2, a struct declaration and some typedefs.

header.h is included in both helper.c and in mainfile.c (helper.h also has include guards, so double declarations aren't a problem.). The functions foo1 and foo2 are defined in helper.c

If I include helper.h in any .c file, my understanding is that the contents of helper.h are literally pasted (word for word) in the .c file at run time. Is my understanding correct?

I used to think that if I call foo1 in mainfile.c the control transfers to the start of foo1, and that foo1 can't interact with anything else defined in helper.c. But there is something wrong with that line of thinking because when I declare a global variable in helper.c, both functions are able to access it. So what does happen when mainfile.c calls foo1 or foo2?

My understanding of the static storage class is that it converts a local variable into a global variable, as all the functions are able to access it. So if I declare a static array in foo1 and then call foo2 in mainfile.c, will foo2 be able to access this static array?

The content of dictionary.c should be something like this

void foo1 (void)
{
    static int array[10] = {1,2,3,4,5,6,7,8,9,10}
    //more code 
}

void foo2 (void)
{
    array[7] = 4;
    // more code
}

When foo2 is called from mainfile , will it be able to access the static array.

Aymen
  • 393
  • 1
  • 3
  • 10
  • Not necessarily "literally", e.g. GCC adds [linemarkers](https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html) within and also reduces whitespaces. – Grzegorz Szpetkowski Aug 04 '14 at 12:53
  • 4
    It would be much better if you could create a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) and show us what you really mean. – Some programmer dude Aug 04 '14 at 12:54
  • 2
    *If I include helper.h in any .c file, my understanding is that the contents of helper.h are literally pasted (word for word) in the .c file at run time. Is my understanding correct?* This happens at compile time, not run time. Formally this is the fourth (out of 8) phase of program translation as defined by the C standard. See [this SO answer](http://stackoverflow.com/questions/1476892/poster-with-the-8-phases-of-translation-in-the-c-language). – n. m. could be an AI Aug 04 '14 at 13:08
  • "My understanding of the static storage class is that it converts a local variable into a global variable" - nope, that's not even remotely close to what `static` is for. – The Paramagnetic Croissant Aug 04 '14 at 13:11
  • I've added an example. I hope the question is clearer now – Aymen Aug 04 '14 at 14:22
  • 1
    When you make a local variable static, it persists beyond the function lifetime for other things to potentially *access*, but without some other help they won't be able to *find* it. – Chris Stratton Aug 04 '14 at 15:11

3 Answers3

3

Both mainfile.c and helper.c are separate translation units, that yields into individual object files (that are subject to linker). An an ilustration you can compile them seperatetly producing .o files (or .obj on Windows platform):

gcc -c helper.c
gcc -c mainfile.c

then examine their symbols e.g. by nm command. In order to link them use the following:

gcc helper.o mainfile.o

When foo1 is called from mainfile.c, that function has access to its own "global variable" (that is defined in helper.c) and it doesn't matter if that variable has internal or external linkage (note that local variables have no linkage). The real thing is that mainfile.c might have (direct) access to it as well (that is, beside foo1 function) only if such variable has external linkage (it's defined outside any function and doesn't have static storage class). This also requires proper declaration, advisable way is to declare it in helper.h using extern storage class, without inializer, e.g.:

extern int global_variable;

Note that this checks declaration againt definition (as you include "helper.h" header inside helper.c source file).

Update:

As pointed by @jweyrich there is possibility to "bypass" internal linkage of global variable, so it's available (with their address) to "consumer" file source. Here is an short example:

b.h:

int *get_secret(void);

b.c:

#include "b.h"

static int secret = 999;

int *get_secret(void) {
    return &secret;
}

a.c:

#include <stdio.h>
#include "b.h"

int main(void)
{
    int *a;

    a = get_secret();
    printf("%d\n", *a);

    return 0;
}

Even secret global variable has internal linkage (as it has static storage class) it can be accessed in a.c. The same technique applies to functions, when some function returns pointer of function declared with static.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • Is it not possible then for mainfile to have access to a variable declared in foo1. – Aymen Aug 04 '14 at 14:30
  • @Aymen: No, it's possible, but only if such variable has **external linkage** and mainfile has declaration with `extern` keyword (but not defition) of this variable (possibly from header file, that is included to it). As opposite you can e.g. declare variable, but not define it anywhere and linker will return an error like "undefined symbol". – Grzegorz Szpetkowski Aug 04 '14 at 14:48
  • @GrzegorzSzpetkowski: when he says `foo1`, I believe he is talking about a function (according to the question), not a compilation unit. So it's not possible unless the function is returning a pointer to that variable. – jweyrich Aug 04 '14 at 14:50
  • @jweyrich: I understand your point, but it's more like "bypassing internal linkage" of some variable. C is not the best language when it comes to things like encapsulation. – Grzegorz Szpetkowski Aug 04 '14 at 15:01
  • @GrzegorzSzpetkowski: Failed to follow you. _Who_'s "bypassing internal linkage"? Are you referring to pointer arithmetic? I just replied because (from what I understood) you mentioned `it's possible` for `foo2` (a function) to access an static variable declared within `foo1` (another function). – jweyrich Aug 04 '14 at 15:06
  • Ah okay, after your update I see what you meant by `bypassing internal linkage`. I think OP's doubt is regarding function-scoped static variables, but the same principle applies. +1 from me :-) – jweyrich Aug 04 '14 at 15:13
  • @GrzegorzSzpetkowski: Now I get it. Thank you. +1 from me too – Aymen Aug 04 '14 at 15:20
2

If I include helper.h in any .c file, my understanding is that the contents of helper.h are literally pasted (word for word) in the .c file at run time. Is my understanding correct?

Partially correct. It's during compilation, not at run time.

I used to think that if I call foo1 in mainfile.c the control transfers to the start of foo1, and that foo1 can't interact with anything else defined in helper.c. But there is something wrong with that line of thinking because when I declare a global variable in helper.c, both functions are able to access it.

Yeah, it's wrong. A compilation unit can reference symbols from other compilation units given that those symbols are exported, e.g: non-static functions, non-static global variables, etc.

Even if a non-static variable is not exposed via header (helper.h), it may gain visibility by declaring it with extern in your compilation unit.

So what does happen when mainfile.c calls foo1 or foo2?

Nothing special. The only difference is that foo1 and foo2 (implemented in helper.c) can see all functions and global variables with static storage from their own compilation unit.

My understanding of the static storage class is that it converts a local variable into a global variable, as all the functions are able to access it. So if I declare a static array in foo1 and then call foo2 in mainfile.c, will foo2 be able to access this static array?

If that static array is global, all functions from the same compilation unit can access it, regardless of who's calling them.

UPDATE:

So if I declare a static array in foo1 and then call foo2 in mainfile.c, will foo2 be able to access this static array?

Nope. The array you're trying to reference is declared within foo1, whose scope foo2 has no access to.

jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • *Nothing special. The only difference is that foo1 and foo2 (implemented in helper.c) can see all functions and variables with static storage from their own compilation unit.* So will a static variable declared in foo1 be visible to foo2? – Aymen Aug 04 '14 at 14:25
  • @aymen: Nope. I meant global static variables, not function scoped. Fixed wording. Thanks! – jweyrich Aug 04 '14 at 14:45
  • Is it not possible then for mainfile to have access to a variable declared in foo1 – Aymen Aug 04 '14 at 14:49
  • @Aymen: Correct. Unless you make `foo1` return a pointer to it. Example: `int * foo1(void) { static int array[] = { ... }; return array; }`. This way you can call `foo1` to get a pointer to its static array, and change it as you wish. – jweyrich Aug 04 '14 at 14:55
1

The key thing you're missing is the so called "compilation unit scope". Each .c file is compiled separately. The result is a object file that exposes all the symbols defined on the global scope.

After compilation comes linking. The linker collects all the compilation units and throws them all into a single large bucket. From there it makes the connection between all the symbols of all the compilation units used by the program (this also means libraries).

My understanding of the static storage class is that it converts a local variable into a global variable

Actually it's exactly the opposite. A global scope variable declared static will not be exposed by the compilation unit and hence will not be used by the linker for program wide symbol resolution.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 3
    also static for global and local variable means different things – zoska Aug 04 '14 at 14:23
  • @zoska: Could you please elaborate. What does static for a local variable mean? My understanding is that static is same for both local and global variables. – Aymen Aug 04 '14 at 15:22
  • 1
    @Aymen: static in a local scope (within a function) the value of the variable is retained between function calls. In a multithreaded program this means that the function looses re-entrancy (i.e. if two threads call the function at the same time things will get messes up). – datenwolf Aug 04 '14 at 15:45
  • 1
    @Aymen, @datenwolf: To be language-purist that means that local variable has *static storage duration*, which means it has lifetime of the **whole** execution of program (as opposed to *automatic storage duration*, note that `auto` keyword (storage class) is never needed, as local variables are implicitly automatic). Specifically for that reason e.g. variable length array (VLA) cannot be declarared with `static` locally (an globally of course), as their size is known run-time. As you probably observed C language abuses use of `static` keyword. – Grzegorz Szpetkowski Aug 04 '14 at 15:58
  • 1
    @GrzegorzSzpetkowski: Yes, I know. But I didn't want to blast Aymen, obviously a C newbie with that information. – datenwolf Aug 04 '14 at 16:42