Static 2D array in multiple files in C - c

I use a 2D array of chars that should be written & read by multiple functions in C.
This is my array:
static char array[3][6];
And let's say I have a function 'Function()' that modify this array.
If the function is defined in the main there is no problem (the the array is correctly written & then read), but if I want to have my Function in an another file, the array is correctly written but when I return in the main is magically empty!
This is my code.
main.c
#include "support.h"
int main(int argc, char *argv[])
{
Function();
unsigned i, j;
for(i = 0; i < 3; i++)
{
for(j = 0; j < 6; j++)
printf("[%c]", array[i][j]);
printf("\n");
}
system("PAUSE");
return 0;
}
support.h
static char array[3][6];
support.c
void Function()
{
char hello[6];
hello[0] = 'H';
hello[1] = 'E';
hello[2] = 'L';
hello[3] = 'L';
hello[4] = 'O';
hello[5] = '\0';
strcpy(array[0], hello);
}
No compilation error nor runtime error. One again, if I try to move everything in main.c all works, if I divide in two files it doesn't (the array is correct as soon as it returns from the Function(), then it is freed), how is it possible?

By declaring array as static in a header file, you give each source file which includes support.h its own copy. You need to change the header to
extern char array[3][6];
and add
char array[3][6];
to a single source file.

The whole point of declaring a file-level entity static is to give it internal linkage, i.e. to ensure that the entity is not visible to the other translation units and that each translation unit gets its own independent copy of such entity. That applies to both functions and objects. In your case each translation unit that includes support.h gets its own independent copy of array object. This is exactly what you achieved by declaring a static array in a header file. And that is why main.c cannot see any modifications made in support.c - these two translation units work with two completely independent arrays.
Now, when I say that the array "is not visible" from other translation units, I mean that you will not be able to refer to it by name from other translation units (i.e. you will not be able to link to it). This is not necessarily a bad thing. If you still want to declare your array as static and access it from other translation units, you can still implement this access "manually": define that array as static in one translation unit and then pass that array to all other functions as a parameter.
(Note, that in most cases passing your array around through function parameters might be a much better idea than introduction of a global variable. And that will even allow you to declare your array as local object in main.)
But if you insist on a genuine global variable, you should stop using static. Declare your arrray in the header file, per #simonc answer, and define it in one of the translation units as an object with external linkage.

Well, you have, actually, two array defined in your program: one in the compile unit main and other in compile unit support. Compiler will compile main.c by one side and support.c by the other side, typically creating object files (usually .obj or .o). The linker put both together, resolving addresses.
Because you are defined the array as static:
static char array[3][6];
you are telling to the compiler the array is private to the compile unit. And because both main.c and support.c are including support.h, both are creating its own private array. Code in main only can see the array defined in main.c, and code in support.c only can see the array defined in support.c. When you call to Function(), that is modifying the array in support.c, not the array visible in main.c.
If you remove the static keyword from the array definition in support.h, you will have a linker error, since that symbol is defined twice (in main.c and in support.c). You must decide where do you want to define the array (in support.c or main.c) and reference to it from the other source file using the extern keyword.

Related

Global static variables shared in multiple source files

While learning about extern and static variables in C/C++, I came across this answer.
Maybe I'm missing some point, but this answer raised doubts about a code of mine.
Suppose I have the following files:
header.h
static int global_foo = -1;
void doSomething(void);
source1.c
#include "header.h"
void doSomething(void) {
global_foo = 1;
}
main.c
#include "header.h"
int main(void) {
doSomething();
printf("%d\n", global_foo);
}
What exactly is the output of the printf in the main function? My interpretation is that since global_foo is included two times, there will be two distinct global_foo, and therefore one such change will affect only the global_foo of the file that it belongs to.
Your assessment is correct.
Because global_foo is declared static, each source file has its own distinct variable by that same name, and a change to one does not affect the other.
Because of this, the program will print -1, since the global_foo in main.c is unchanged.
Global variables have static storage duration anyway so there's no need to include the static qualifier to explicitly state its storage duration. When you declare a global variable as static within a translation unit you are just saying that it has internal linkage within that translation unit. This means it can only be identified by its name within the translation unit.
So, if you declare a variable as static in a header file, every translation unit that includes it gets its own copy of the variable that is different from all the others.
If you have a function that returns the address of the variable, i.e.
int *getStaticAddress ()
{
return &static_var;
}
You can use that to access the variable outside the translation unit.

C - void function(void), parameters and return values

I was given a large C-file containing several functions declared as follows:
void function_a(void);
The functions are written above the main program:
static void function_a(void) { .... }
Within the main program these functions are called as:
function_a();
Now as far as I know a function declared as written above does neither use parameters, nor have return values. However within these functions variables and arrays are used, which are not defined within these functions, but only in the main program.
Is this really correct C-Syntax? How can the functions access data from the main program, if it is not handed over as a parameter?
In addition the main program uses variables, which are calculated within the functions it calls.
Can you provide more context, please? In C you cannot access variables from another function but you can access global ones.
The following program is valid and will output 3, since i is a global variable and is visible everywhere.
#include <stdio.h>
int i = 2;
void plusone() {
i = i + 1;
}
int main() {
plusone();
printf("i = %d\n", i);
}
On the other side, the program below won't compile because i is local to main() function and is invisible elsewhere.
#include <stdio.h>
void plusone() {
i = i + 1;
}
int main() {
int i = 2;
plusone();
printf("i = %d\n", i);
}
Said that, usage of global variables is a bad practice and should be avoided.
So this:
//file_a.c
void function_a(void)
{
//...
}
Makes function_a a function that does not take any arguments and does not return any values. This function may be used by all other functions in the same file function_a was declared or in any other .c file that you tell the compiler to put together into the final program.
In other words, this function is accessible to all translation units of your program. If you have this function in a file called file_a.c, and you also have another file called file_z.c you can do this:
//file_z.c
void function_z(void)
{
function_a();
}
And all is fine.
On the other hand, this
//file_b.c
static void function_b(void)
{
//...
}
(and I renamed the function for clarity)
Makes function_b a function that does not take any arguments and does not return any values, just like function_a. However, it also says that function_b has static-file scope in the translation unit that begins or includesfile_b.c. That means it cannot be accessed by other translation units.
So if you now tried to do this in file_z.c:
void function_z(void)
{
function_b();
}
You would get compilation errors:
file_z.c:(.text+0xa): undefined reference to `function_b'
collect2: error: ld returned 1 exit status
Because each file_{a,b,z}.c is (or probably should be) the starting point of their own separate translation units, and function_b was declared with static-file scope in file_b.c, this function simply "does not exist" for other translation units.
Now, as to the variables declared just before function_b, I take they look somewhat like this:
//file_a.c
int array[10];
void function_a(void)
{
//...
}
That simply declares a global variable. It can be accessed by all functions in file_a.c, provided that they appear after the declaration. It can also be used by other translation units (like file_b.c or file_z.c) if you declare it like this:
//file_b.c
extern int array[10];
When you compile everything togheter, that declaration in the translation unit that starts with file_b.c will tell the compiler that array is not a file-scope variable within that file_b.c; rather the compiler will have to look for that variable in another translation unit, and then link them together so that all functions do the same thing to that block of 10 integers.
In C it is not at all possible to access local variables of another function or even scope.
Is the code compiling correctly? If yes these variables must be global defined either in the beginning or some header file.
If not make them global to access from non-parametric functions.

How to make the array packets private and accessing them in C

I wanted to know how could i make my code better by declaring the array 'data_pack[]' as a private .Im working in embedded field so i have limited RAM and Memory and all i wanted to do is two things.
1.I have a serial UI which gives me serial data of 50 Bytes and stores them directly to unsigned char data_pack[50]
2.And I wanted to access the array in another module to calculate and do other things.
Currently im keeping the array as global variable and can be accessed from any module in my project.If i wanted to keep data_pack[50] as private how can i access the array packets in another modules?
I hope i will be more clearer after explaining here:
I have four modules.
main.c
ui.c
display.c
display2.c
And If i wanted to keep data_pack[50] as pvt in ui.c and access it in other modules..how can i do it with out making it global.
For eg: In ui.c I would like the data_pack[] to get filled in and in
display.c and display2.c I want to access the array and read its
element.In that case how could i pass the array in to other source
files
What would be the best way to access data_pack[] by keeping it as private?
Or should i use structures instead?
You can make a global variable data_pack read-only in other compilation units by changing its forward reference to extern const .... For example, two files:
file1.c
char example[50] = {1, 2, 3};
void change() {
example[1] = 44;
}
file2.c
#include <stdio.h>
/* extern const char example[50]; array size not needed in extern declaration */
extern const char example[];
void change();
int main() {
printf("%d\n", example[1]); /* works */
change();
printf("%d\n", example[1]);
/* example[0] = 45; would cause a compile error */
return 0;
}
Therefore, file2.c will see example as an array of constant ints, meaning it can only be modified by file1.c. The code above would print 2, followed by 44.
However, you must be careful doing this. If the size of the array in the forward declaration differs from the actual size of the array in the compilation unit it is contained in, the compiler/linker will not tell you (at least it doesn't for me, using gcc -Wall -Wextra -ansi -pedantic). You can also leave the array size out of the extern declaration.
One thing to note is that the compiler may attempt to optimize the const value, as it may not expect the value to change, thus producing invalid optimizations. I've performed some tests, and GCC doesn't seem to do this, but as it is undefined behaviour you may wish to use a getter/setter solution instead.

Static variables in C accessed from another file

I have two C-files, each having defined a static int variable sharing the same name.
My understanding is that static variables declared at top-level should be limited to usage within the same file.
However, when I run my program it is obvious that these files affect the value of one another's static variable.
Have I misunderstood how the static keyword works and is there another way to obtain this file-based separation of scopes?
*Edit: Added source code to demonstrate problem. This code is from 3 separate files, as indicated by the comments.
//file 1
static int buffer;
void setter_1(int *input) {
buffer = *input;
}
void getter_1(int *output) {
*output = buffer;
}
//file 2
static int buffer;
void setter_2(int *input) {
buffer = *input;
}
void getter_2(int *output) {
*output = buffer;
}
//main
#include <stdio.h>
#include "buffer_1.c"
#include "buffer_2.c"
int main() {
int int1 = 1;
int int2 = 2;
setter_1(&int1);
setter_2(&int2);
getter_1(&int1);
getter_2(&int2);
printf("%i, %i\n", int1, int2);
return 0;
}
We expected to get two different numbers ("1, 2"), but got two identical numbers ("2, 2").
Thanks in advance
/Frisch
Even though we often talk about the structure of C program in terms of "files", most of the time what is really meant by "file" is translation unit - a source file together with everything that is #included into it.
Now, static variable in C means a variable with internal linkage, i.e. a variable that is not linkable by name between different translation units. Each translation unit is such case gets its own, completely independent variable. Having multiple translation units in this case is absolutely critical: the separation in question is only possible, again, between different translation units.
In your example you have only one translation unit: you included your .c files into a single main.c file, i.e you merged all of your translation units into one translation unit. The title of your question refers to static variable "accessed from another file". In reality there's no "another file" in your example. You have only one "file".
Since you merged everything into a single translation unit, your static variable declarations became repetitive declarations of the same variable inside one translation unit.
Note that your static variable declarations happen to be definitions at the same time. In C++ such repetitive definitions of the same variable would trigger a "multiple definition" error. In C such definitions are treated as tentative definitions (a C-specific feature), which allows them to slip through. But if you add explicit initializers to your static variables (e.g. static int buffer = 0;) the definitions will no longer be tentative and the code will fail to compile even in C.
If you want to maintain different, independent variables in this case, stop including your .c files into your main.c file. Translate each .c file independently, as a separate translation unit, and then link them together into the final program.
One way this can happen is when pointers to those static variables are passed between functions in the two files:
file1.c:
static int i1;
...
foo(&i1);
file2.c:
void foo(int *ip)
{
*ip = 42;
}
Calling foo in file1.c would modify i1 from a function outside file1.c
I suppose by inclusions you have effectively declared the same static global variable twice, which is why you no longer have two separate variables, but one.
The way you did it, by including file 1 and file 2 in main, you effectively have only one "buffer" variable.

Incrementing a global static int in main

Here's my code:
File DataTypes.h
static int count=0;
File TreeOps.h
#include"DataTypes.h"
void printTree(Tree* ptr)
File TreeOps.c
#include"TreeOps.h"
void printTree(pointer){
count++; // incrementing the count;
printf("%d",counter);
}
File TreeMain.c
#include"TreeOps.h"
printTree(pointer); // all the necessary declarations are done.
printf("%d",count);
If in printTree function the printf gives count=1; while in main function it gives me 0.
Why?
static variable in this context means: every c file has its own variable instance. Remove static definition in h-file:
extern int count;
and add this to one of c files:
int count = 0;
extern means: this is forward declaration. By defining a variable as extern, you tell to compiler that count has int type, and this variable is created somewhere. Actually, this variable is created in one and only one c file. You can use it in any c file where DataTypes.h is included. In the file where this variable is created, compiler uses it. In all other file this variable becomes external reference, which is resolved later by linker.
First off, defining data or functions in header files is a bad practice in C programming. In DataTypes.h you don't just declare the count variable, but you define it.
What actually happens is that the count is defined separately in each translation unit and you end up with two variables after linking. The linker doesn't merge them because they are marked static, that means they should be local to the translation unit.
If you want the count variable to be shared between the TreeOps.c and TreeMain.c translation units, you must use extern in the header file which only declares it:
extern int count;
And then define it globally as int count in either of TreeOps.c or TreeMain.c.
You don't have a "global static int" in your program. Entities declared as static cannot possibly be "global". The whole point of declaring something static is to make it local to a specific translation unit. This is exactly what you've done: you have declared two completely independent static variables in two different translation units. Each variable is local to its own translation unit. Then you are modifying one of these variables and printing the other. No wonder that the other remains unchanged.
In this case you have to decide what it is exactly you want. You can either have your variable as a global variable or as a static variable, but not both at the same time. "Global variable" and "static variable" are mutually exclusive concepts. So, what is it you want: global or static?

Resources