Resolve 'undefined reference' to a global external array variable - c

I have a header constants.h file, with the following declarations of an array variable:
extern storageCommandData storageCommands[];
The type of the array is defined elsewhere, and is not relevant to the question.
In another source file (.c) I initialized the array like so:
#include "constants.h"
storageCommandData storageCommands[STORAGE_COMMAND_NUM] =
{
/*storageCommandData intilazation follows the
following template: {commandName, storageSize}*/
{".db", 1},
{".dw", 4},
{".dh", 2},
{".asciz", 0},
};
I tried to use these arrays in another source file (a different one than the one I define the arrays in), by including constants.h.
However, when I try to use the variable storageCommands I get the following error message:
undefined reference to `storageCommands'
How do I fix the error?

Using extern means that you are using a variable that is declared in another translation unit (i.e. basically a source file and the headers it includes). It is the linker's task to relate the extern-specified variable name to its actual declaration. If the linker cannot find the latter, it will report an "undefined reference".
As already pointed out in the comments, the most common cause of this error is that the source file containing the actual declaration was not compiled or linked.

Related

Can't resolve C warning in STM32CubeIDE

Facing a a warning which I am not able to get rid of. I am using stm32 MCU and STM32CubeIDE with a standard C11 compiler. Array gpioOutPins is used by in a function call gpio.c file. This function which contains this function call is called from inOut.c file.
Please note that the inOut.c file is in User Application layer while the gpio.c file is in the Kernel (Core) section of the project tree as can be seen below. I was not able to accommodate the whole project tree in the snapshot.
I don't understand why this warning is generated.
Any help is appreciated. Thank you.
An array is deifned in a header file gpio.h:
static uint16_t gpioOutPins[GPIO_OUT_CH_NR] =
{
DOUT_OD_OUT4_Pin,
DOUT_OD_OUT6_Pin,
DOUT_OD_OUT5_Pin,
DOUT_OD_OUT7_Pin,
DOUT_LED_DISABLE_Pin,
DOUT_BUZZ_Pin,
DOUT_OD_OUT8_Pin,
DOUT_OD_OUT3_Pin,
DOUT_OD_OUT2_Pin,
DOUT_OD_OUT1_Pin,
DOUT_ALARM_Pin,
DOUT_12V_PWR_Pin,
DOUT_12V_PWR_Pin
};
The directory structure looks like this:
The warning generated by the compiler is this:
warning: 'gpioOutPins' defined but not used [-Wunused-variable]
Header (.h) files are not a good place to define global variables, because when they are included in source (.c) files, multiple independent copies of them come to existence. They share the same name, but they are actually different variables. And if they are not static, the linker rejects them because of multiple definitions.
Your inOutTask.c probably includes gpio.h header directly or indirectly, so another copy of gpioOutPins comes into existence, which is distinct from the one used in gpio.c. Because you don't use gpioOutPins in inOutTask.c, you get the warning.
The proper way is to move the definition into gpio.c, remove the static keyword, and add extern uint16_t gpioOutPins[GPIO_OUT_CH_NR]; to gpio.h

Multiple includes of the same source files through a project is correct?

I'm trying to call a method in my main, which is declared in another file.
When I try to call it with this line of code in the Main.c:
#include "SPI3.c"
void main(void) {
initSpi();
}
it gives the following error:
SPI3.c:196:: error: (237) function "_initSpi" redefined
The function is declared in the file SPI3.c
void initSpi()
{
//CODE
}
I've researched thoroughly my code and there is no redefinition of the function, and searching through the web I've seen that the error also appears when you call a function that is not declared yet or when
you include the same file more than once and it redefines the function.
I'm certain it's the former because I actually do more than one include of this file in the project, because I also need to call those methods in other files.
What am I doing wrong? There can only be one include of a source file in the whole project? Or is there another solution? Could it be that the function is just not initialized?
Thanks, feel free to ask for more details.
By including any file, you paste its contents into your file. So, the function initSpi() is defined twice: within SPI3.c and Main.c => you get redefinition. You need to include only .h headers not .c files. These header files contain only declarations (opposed to definitions), e.g.:
/* SPI3.h */
void initSpi();
So, we include header files into our file and get declarations of functions and variables that are defined elsewhere. In order to link their definitions, we can possibly need also a Makefile or a C project file.
You should not include .c files, but .h files (except if you know exactly what you are doing).
I would rather do the following thing:
in your SPI3.h file, declare your function:
void initSpi(void);
Don't forget Include guard in your .h file
and in your main.c file:
#include "SPI3.h"
Thus your function is only defined once (in your SPI3.c file), and you will not get the redefined error.
Just for clarification
When you write the following code in your .c file:
void initSpi()
{
//CODE
}
Then you both declare and define your function.
When you write the following code in your .h file:
void initSpi(void);
Then you just declare your function. It is your function prototype.
Your function can be declared multiple times, but can only be defined once (except if using the weak keyword).
That why it is recommended to declare (and only declare) your functions in .h files and to only include those files into your .c files.

how to solve this c linker error?

uint8 *measurements[30] = {(uint8*)0x0041c620};
I have declared a global variable in my program like above but I am getting a linker error as
LNK2005: _measurements already defined in MAIN.obj
I am modifying the code as
typedef unsigned char uint8;
uint8 *measurements[30];
measurements[30]= {(uint8*)0x0041c620}
;
then also I am getting the error
The error tells you that you have defined this global variable in more than one translation unit - in MAIN.obj as well as in some other. Which one I cannot tell, because you didn't post the whole error message, only one line of it.
Your question does not contain enough information to reproduce the problem, or tell where exactly you made the error. Perhaps you defined the variable in a header file?
Is the definition in a header file? If so, you'll get one definition of the variable for each source file that includes the header. Try marking changing the header to only declare the variable, not define it, like so:
extern uint8_t *measurements[30];
and then define it in one of the files, e.g. main.c like so:
uint8 *measurements[30] = {(uint8*)0x0041c620};
It seems you want array of 30 8-bit values, and that array is already existing at some specific address.
In one source file (measurements.c):
uint8 * const measurements = (uint8*)0x0041c620;
In header file (measurements.h):
uint8 * const measurements;
Usage:
#include "measurements.h"
// In some function
measurements[29] = ... // Set last element to something
Note that I added the const because I think you do not want to change array address (0x0041c620).

Declaring,initializing and using a global variable in same header file

I am actually trying to use a variable that is initialized in a header file(say x.h) and want to use same variable inside inlined code in the same header file. The same variable is modified in another file (say y.c). How can i do this ? I would like to know a good way of doing this.
Using the extern reserved word.
Never create variables in '.h' files, it's a bad practice that leads to bugs. Instead, declare them as extern everywhere you need to use them and declare the variable itself only in a single '.c' file where it will be instantiated, and linked to from all the other places you use it.
You can declare the global variable in the header file as extern, and then define it inside a code-module (i.e., ".c" file). That way you won't end up with multiple definition errors thrown by the linker.
So for example in your header file, a globally available int named my_global_var would have a declaration in a .h file that looks like:
extern int my_global_var;
Then inside a single .c file somewhere you would define and initialize it:
int my_global_var = 0;
Now you can use my_global_var in any other code module that includes the appropriate header file and links with the proper .c file containing the definition of the global variable.

initializing a static variable in header

I am new in programming in C, so I am trying many different things to try and familiarize myself with the language.
I wrote the following:
File q7a.h:
static int err_code = 3;
void printErrCode(void);
File q7a.c:
#include <stdio.h>
#include "q7a.h"
void printErrCode(void)
{
printf ("%d\n", err_code);
}
File q7main.c:
#include "q7a.h"
int main(void)
{
err_code = 5;
printErrCode();
return 0;
}
I then ran the following in the makefile (I am using a Linux OS)
gcc –Wall –c q7a.c –o q7a.o
gcc –Wall –c q7main.c –o q7main.o
gcc q7main.o q7a.o –o q7
the output is 3.
Why is this happening?
If you initialize a static variable (in fact any variable) in the header file, so if 2 files include the same header file (in this case q7.c and q7main.c) the linker is meant to give an error for defining twice the same var?
And why isn't the value 5 inserted into the static var (after all it is static and global)?
Thanks for the help.
static means that the variable is only used within your compilation unit and will not be exposed to the linker, so if you have a static int in a header file and include it from two separate .c files, you will have two discrete copies of that int, which is most likely not at all what you want.
Instead, you might consider extern int, and choose one .c file that actually defines it (i.e. just int err_code=3).
When you declared a variable as a static it has only scope within a file ie.., it can be accessed only within a file.
When you declare a static variable in a header file and include this header file in two .c file, then you are creating two different
memory for two different ".c" files
When you print err_code directly in the Main function you would see its value as 5 instead 3,
but you are calling a function printErrCode which is defined in a different file "q7a.c" for which err_code has a different memory location
in which err_code memory is still 3 and it not updated and that is why you are getting the value as 3 instead of 5.
Since two memory is created and err_code is considered as two different variables having different memory with different file scope you will not see any linking errors.
The static variables do not have external linkage which means they cannot be accessed outside the translation unit in which they are being defined. So in your case when q7.h is #include'ed in both translations units q7a.c and q7main.c ... two different copies exists in their corresponding .o files. That is why linker does not report error becuase both copies are not seen by linker while doing external symbol linkage.
While doing small research came to know that we can declare variable in Header file but in one of the source file includes that should have definition for that variable.
Instead if we define a variable in header file. in the source files where this header file included, definitions will be created which causes multiple definitions.
A static variable should be declared with in the file where we use it shouldn't be exposed to header file.
Hope I am giving right information. If I am wrong feel free to correct my statements in your comments.

Resources