In C language, Static Variable with pointer access - c

My question is about Memory and how it is being accessed across a program with multiple C files (Multiple Modules).
file1.h Version 1
#ifndef file1_h
#define file1_h
typedef struct
{
UINT8 var1;
UINT16 var2;
UINT16 var3;
} TestAccess;
static TestAccess* pLongRangeAccess;
#endif
file1.h Version 2
#ifndef file1_h
#define file1_h
typedef struct
{
UINT8 var1;
UINT16 var2;
UINT16 var3;
} TestAccess_t;
TestAccess_t* pLongRangeAccess;
#endif
Main.c
#include "file1.h"
void main(void)
{
pLongRangeAccess->var1 = 4;
pLongRangeAccess->var2 = 8;
pLongRangeAccess->var3 = 16;
}
Module1.c
//Needs read/write access to the struct variables
#include "file1.h"
void module1(void)
{
pLongRangeAccess->var1 = 5;
pLongRangeAccess->var2 = 10;
pLongRangeAccess->var3 = 20;
}
Question 1) See "Version1" Does static in keyword make it such that there will be only one copy in heap memory (uninitialized) and therefore only one address of the pointer variable OR would it create 2 static variables with different memory since the header is used in every module?
Question 2) see "Version 2" If static was not declared for the pointer variable, then it would still be in heap memory and there would be one UNIQUE address that could be used to accessed to read and write operations to the members?
Question 3) In version 2 of file1.h if the pointer was declared in Main.c, and the memory location was fixed i.e it was declared as a constant, would it be available for access from any module by de-referencing the memory address location?

I think you are mixing up "memory allocation" with variable declaration and variable definition. I think what you want is to share a variable pLongRangeAccess among different translation units, such that it exists only once in your program. To do that, declare the variable in the header file, and define it once in a single c-file:
#ifndef file1_h
#define file1_h
typedef struct
{
UINT8 var1;
UINT16 var2;
UINT16 var3;
} TestAccess;
extern TestAccess* pLongRangeAccess;
#endif
And then the .c-file:
// file1.c:
#include "file1.h"
TestAccess* pLongRangeAccess;
Note that keyword static, when applied to variables outside any function, means that this variable is private to the respective translation unit; this is mainly for information hiding and for avoiding unintended name clashes with other translation units (from different vendors, probably).
So, if you write
// file1.c
static TestAccess* pLongRangeAccess;
// file2.c
static TestAccess* pLongRangeAccess;
, then translation unit file1 and file2 both have their own private variable pLingRangeAccess, which is not visible to other translation units (regardless if any head file declares the variable as extern). The linker will not complain any "duplicate variable definition" in this case, as - as mentioned - the variables are private to their TU.
If you write, however, the following
// file1.c
TestAccess* pLongRangeAccess;
// file2.c
TestAccess* pLongRangeAccess;
, then both variables become visible to the other translation units, and the linker will complain that variable pLongRangeAccess is defined twice in your program, which is not allowed.

Related

Best way to share multiple global variables between compilation units in C

I am trying to 'gather' global cmdOps spread in multiple files into lookup table for convenient usage in main. I did as shown below, but as pointed out this approach does not guarantee file1.c and file2.c to use the same variables, but I really want to avoid using extern declarations in file1.c as there will be tens of them if not more.
main.c:
#include "file1.h"
int getLutIdx(int argc, char *argv[]);
extern myLUT *LUT;
int main(int argc, char *argv[])
{
int idx = getLutIdx(argc, argv);
myArgs args;
LUT[idx].ops->parseArgs(argc, argv, &args);
LUT[idx].ops->validateArgs(&args);
LUT[idx].ops->executeCmd(&args);
}
file1.h:
typedef struct myArgs {
union {
cmd1Args_t cmd1Args;
cmd2Args_t cmd2Args;
...
}
}myArgs;
typedef int (*op1)(int argc, char *argv[], myArgs *args);
typedef int (*op2)(myArgs *args);
typedef int (*op3)(myArgs *args);
typedef struct cmdOps {
op1 parseArgs;
op2 validateArgs;
op3 executeCmd;
} cmdOps;
typedef struct myLUT {
char *cmdName;
cmdOps *ops;
}myLUT;
file1.c:
#include "file1.h"
#include "file2.h"
#include "file3.h"
myLUT LUT[CMD_NUM] {
{ "CMD1", &cmd1Ops },
{ "CMD2", &cmd2Ops },
...
}
file2.h:
int cmd1ParseArgs(int argc, char *argv[], myArgs *args);
int cmd1ValidateArgs(myArgs *args);
int cmd1Execute(myArgs *args);
int cmd2ParseArgs(int argc, char *argv[], myArgs *args);
int cmd2ValidateArgs(myArgs *args);
int cmd2Execute(myArgs *args);
cmdOps cmd1Ops;
cmdOps cmd2Ops;
file2.c
#include "file1.h"
#include "file2.h"
myOps cmd1Ops = {
.parseArgs= cmd1ParseArgs,
.validateArgs = cmd1ValidateArgs,
.executeCmd = cmd1Execute
}
myOps cmd2Ops = {
.parseArgs= cmd2ParseArgs,
.validateArgs = cmd2ValidateArgs,
.executeCmd = cmd2Execute
}
...
Whole question edited, thanks for previous comments.
Goal is for user to invoke:
./myProg <cmd_name> <cmd_args>
and each command (or sets of commands) can accept different parameters
The "best way" would be to not have any global variables (or at least, as few as possible), since global variables are likely to make your program difficult to understand and debug as it gets larger and more complex.
If you must have global variables, however, I suggest declaring the global variables in just one .c file:
myOps file2Ops; // in somefile.c
... and placing any necessary extern declarations in a .h file that other files can include:
extern myOps file2Ops; // in someheader.h
But it baffles me why don't I get any error or warning about duplicated declaration…
At file scope, myOps file2Ops; is a tentative definition, which is not actually a definition, directly. If there is no definition for it by the end of the translation unit, the behavior is as if there were a definition myOps file20ps = {0};. (Having an initializer would make the declaration a proper definition instead of a tentative definition.)
Then, because myOps file20ps; appears in file2.h and that is included in both file1.c and file2.c, your program has multiple external definitions of file20ps. The C standard does not define the behavior of this because it violates the constraint in C 2018 6.9 5:
… If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.
Historically, some C implementations have defined the behavior of external identifiers resulting from tentative definitions to act as “common” symbols. When linking the object modules, a definition originating from a tentative definition will be coalesced with other definitions, so there will be only one definition in the final program. Your C implementation (notably the compiler and the linker) appears to be doing this, and that would be why you did not get an error message.
(This was the default behavior for GCC prior to version 10. You can request the old behavior with -fcommon or the non-coalescing behavior with -fno-common. Some additional information is here and here.)
… and I also don't know if this approach would be considered 'good practice'
You have not shown much context for what you are doing or why. Generally, external identifiers for objects should be avoided, but there can be appropriate uses.

Define array in header and storing it in stack

I need to define a global array which has to be visible in every file. I declared it in a header file, but it's stored in heap e not in stack. How can i put it in stack? Thank you
EDIT:
I'm using an ATMEGA32 and array is put at the begin of the RAM (address 0x0060), while I need to put it at the end (address 0x085F)
common.h
#define dimension 5
unsigned int board[dimension][dimension];
main.c
#include "common.h"
You have a definition of the array variable in the header file. If you include it in more than one file you will have duplicate (or multiple) definitions of the same global variable which will be reported as an error by the linker.
In the header file you should have a declaration only like
extern unsigned int board[dimension][dimension];
and a definition in exactly one C file at file scope, i.e. not in a function. For example you can use this definition in main.c
unsigned int board[dimension][dimension];
It must be this way if you want to access the variable from more than one .c file.
To put this variable on the stack it must be inside a function, e.g. in main(), but this way you cannot use it as a global variable. You could use a pointer variable as a global variable and initialize this in main() with the address of the array. This has the drawback that the functions that use the pointer cannot determine the two array dimensions from the variable itself. Of course they could use the preprocessor symbol.
Example:
common.h
#ifndef COMMON_H
#define COMMON_H
#define dimension 5
extern unsigned int (*board)[dimension];
#endif // COMMON_H
main.c
#include "common.h"
#include "other.h"
unsigned int (*board)[dimension];
int main(void)
{
unsigned int the_board[dimension][dimension] = {{ 0 }};
board = the_board;
printf("board[1][2] = %d\n", board[1][2]);
some_function();
printf("board[1][2] = %d\n", board[1][2]);
return 0;
}
other.h
#ifndef OTHER_H
#define OTHER_H
void some_function(void);
#endif // OTHER_H
other.c
#include "common.h"
#include "other.h"
void some_function(void)
{
board[1][2] = 3;
}
If you want to have the variable at a specific address or in a specific address range (but not on the stack) you could use a (linker specific) linker script to define a memory section at a specific address range and use a (compiler specific) #pragma section("name") or __attribute__((section("name"))) to put a normal global variable into this memory section.

How to initialize global pointer to extern variable?

Lets say I have the following struct:
typedef struct
{
uint8_t *ptr;
} Example;
If I have in file1.c:
// Global variable
uint8_t myVar;
How can I initialize an Example with the ptr member pointing to myVar, in file2.c?
I know I could just do:
extern uint8_t myVar;
// Global variable
Example myExample = {.ptr = &myVar};
But myVar would be visible in all the scope of file2.c and I'm trying to avoid that.
A pointer or other object can be made available within a source file without making symbols used in its initializers be visible by declaring it extern in one source file (or more) and defining it in a separate source file.
Create a separate C file, such as myExample.c, containing a definition of myExample:
#include "myExample.h"
extern uint8_t myVar;
Example myExample = { .ptr = &myVar };
Create a header file, such as myExample.h, that declares myExample:
typedef struct
{
uint8_t *ptr;
} Example;
extern Example myExample;
Then include the header file in any source file where you want to use myExample. That source file will see myExample but not myVar.
Also compile the new C file and link it in with your program.
you need to add the function in the file.c
static uint8_t myVar;
uint_8 *getMyVat(void)
{
return &myvar;
}
in file2.c
void foo(void)
{
Example myExample = {.ptr = getMyVar()};
}
But it cannot be used as an initialisation of the static storage variables
I am afraid you cannot. C language has only 3 scopes:
global scope is (potentially) visible to the whole program (across different compilation units)
static scope is visible to a compilation unit
local scope is visible to the block where the variable is declared
If you want to initialize a global or static variable, its initializers can only contain global or static symbols, which have to be visible throughout all the source file.

C Programming Error: undefined symbol to a struct (Keil error L6218E)

I am using Keil MDK ARM to develop a project. However, when I am trying to build my code, the software tool throws the ERROR: L6218E : Undefined symbol Bit (referred from main.o).
Where Bit is a struct that I am using to store boolean values. For eg:
In variable.h file
struct
{
unsigned bPowerONStatus : 1;
unsigned bTimerONStatus : 1;
} extern Bit;
In main.c file:
#include variable.h
int main()
{
while(1)
{
ReadTimerStatus();
if(Bit.bPowerONStatus)
{
// System is ON
}
else
{
// System if OFF
}
}
}
In PowerChecker.c file
#include variable.h
void ReadTimerStatus(void)
{
if(Bit.bTimerONStatus)
{
Bit.bPowerONStatus = 1;
}
else
{
Bit.bPowerONStatus = 0;
}
}
What am I doing wrong here? What is the correct method of defining a struct, that will be used in multiple source files?
Declaring a variable at file scope with the keyword extern, but with no initializer declares the variable to have external linkage, but does not define the variable. There needs to be a definition of the variable elsewhere in your program.
In the case of your Bit variable, it has been declared with an anonymous struct type that has no type alias, so there is no way to use the same type when defining the variable. In order to fix that you need to either define the struct type with a tag, or define the struct type within a typedef declaration, or you can do both.
It is more conventional to put the storage class specifier such as extern at the front of the declaration.
In variable.h:
struct StatusBits
{
unsigned bPowerONStatus : 1;
unsigned bTimerONStatus : 1;
};
extern struct StatusBits Bits;
In only one C file, e.g. main.c or variable.c:
#include "variable.h"
struct StatusBits Bits;
Note that the struct StatusBits Bits; above has external linkage and has no initializer, but has not been declared extern, so it is a tentative definition of the Bits variable. Unless overridden by a definition of the same variable with an initializer, it will behave as if it has been initialized with {0}.

variable between files [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I share variables between different .c files?
If I have two source files, and one header: file1.c, file2.c, and header.h, and:
--header.h--
int i;
--file1.c--
#include <header.h>
i = 10;
int main() {
func();
return 0;
}
--file2.c--
#include <header.h>
void func() {
printf("i = %d\n", i);
return;
}
I get the warning that i defaults to an int. What could I do if I want to have i as a float for instance?
Make it
extern int i;
in the header and
int i = 10;
in file1.c.
The warning means that for the (incomplete) declaration i = 10; in file1.c, the "implicit int" rule is applied, in particular, that line is interpreted as a declaration (since an assignment cannot appear outside function scope).
You have a couple of errors in your code. The first is that you define the variable i in the header file, which means that it will be defined in all source files that include the header. Instead you should declare the variable as extern:
extern int i;
The other problem is that you can't just assign to variables in the global scope in file1.c. Instead it's there that you should define the variable:
int i = 10;
Declare it as extern in the header (this means memory for it is reserved somewhere else):
/* header.h */
extern int i;
Then define it in only one .c file, i.e. actually reserve memory for it:
/* file1.c */
int i = <initial value>;
In the header use
extern int i;
in either file1.c or file2.c have
int i = 20;
If you want float just change int to float
In 99.9% of all cases it is bad program design to share non-constant, global variables between files. There are very few cases when you actually need to do this: they are so rare that I cannot come up with any valid cases. Declarations of hardware registers perhaps.
In most of the cases, you should either use (possibly inlined) setter/getter functions ("public"), static variables at file scope ("private"), or incomplete type implementations ("private") instead.
In those few rare cases when you need to share a variable between files, do like this:
// file.h
extern int my_var;
// file.c
#include "file.h"
int my_var = something;
// main.c
#include "file.h"
use(my_var);
Never put any form of variable definition in a h-file.

Resources