compiler says the extern variable is not defined - c

I get "Error[Pe020]: identifier "mVar" is undefined" by IAR compiler for the below code.
How should have I used the extern variable? I couldn't see what I am doing wrong.
//commonDefs.h
#include <stdint.h>
extern uint16_t mVar;
//file1.c
...
uint16_t mVar; //global declaration
...
static void food( void){
mVar = 10;
}
//file2.c
uint16_t compVar;
...
static void mFoo( void ){
if( compVar > mVar){
...
}
}

Declare mVar as uint16_t in the header and use extern when you are reffering to variable that is declared in another source file, that is use extern only in your source files. When you put extern in front of a variable the linker will look for definition elsewhere

Related

Is there any way to access static global variable defined in main.c and modify it in another file?

For example:
In main.c
static glob_var;
I want to modify the value of glob_var in another file say file1.c
Making an variable static makes its identifier inaccessible from other translation unit (what usually means other C-file). You can either
Make the variable non-static.
//main.c
int glob_var;
//file1.c
extern int glob_var;
Note that the declaration should be put to a header file.
Keep it static and add a helper function for access.
//main.c
static int glob_var;
void SetGlobVar(int val) {
glob_var = val;
}
//file1.c
void SetGlobVar(int);
void foo(void) {
SetGlobVar(42);
}
Note that the declaration of SetGlobVar() should be put to a header file.
The comments and other answer address the question of how to access and modify a static global". The following is offed as an alternative to using static for this purpose...
When needing to create a variable that is global and can be changed among several translation units I believe it is more idiomatic to use the externstorage class. This is typically done by:
Declaring the extern variable in a header file
Defining the extern variable one-time-only in a .c file that #includess the header file.
Access and modify the extern class variable from any translation unit that #includes the header file in which the extern is declared.
Example:
in some.h:
void modify_glob_var(int val);
...
extern int glob_var;//declare extern variable
in main.c
#include "some.h"
...
int glob_var = 0;// define extern variable
...
modify_glob_var(10);//access and modify extern variable
in some_other.c
include "some.h"
...
void modify_glob_var(int val)
{
glob_var = val;//value of extern glob_var is changed here
}

bit-declaration - undefined reference to 'variable'

I have problem and hope, that you could help me.
I try to make CAN-communication between two dsPIC30F4011. It also works. Now I have to make the Identifier. I have to use the SID and the EID. They are divided into 4 parts. I want to make a bit-declaration and get an error.
I made a new header-file
#ifndef IDENTIFIER_H
#define IDENTIFIER_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* IDENTIFIER_H */
#include <p30F4011.h>
#include "system.h"
#include <p30fxxxx.h>
typedef struct tagCxTXxSIDBITS{
unsigned : 11;
unsigned PRIO4_0 : 5;
}CxTXxPRIOBITS;
extern volatile unsigned int C1TX0PRIO __attribute__((__sfr__));
extern volatile CxTXxPRIOBITS C1TX0PRIObits __attribute__((__sfr__));
extern volatile unsigned int C1TX1PRIO __attribute__((__sfr__));
extern volatile CxTXxPRIOBITS C1TX1PRIObits __attribute__((__sfr__));
extern volatile unsigned int C1TX2PRIO __attribute__((__sfr__));
extern volatile CxTXxPRIOBITS C1TX2PRIObits __attribute__((__sfr__));
In the Code I want to write
...
...
C1TX0PRIO = 0x0000;
...
If I want to build the project I get the error
build/default/production/CAN_function.o(.text+0x66): In function `.LSM19':
: undefined reference to `_C1TX0PRIO'
make[2]: *** [dist/default/production/blink.X.production.hex] Error 255
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
What did I do wrong?
I wrote it like in the p30F4011.h
You have the variables declared as extern in the header.
Usually you need to put the variable as extern in the header, if you want to use that variable from multiple source files. In this way, the variable will be accessible in all source files which include this header. However, in one of the C files you will need to have the following:
volatile unsigned int C1TX0PRIO __attribute__((__sfr__));
TL;DR- declaration does not allocate memory, definition does.
As per C11 standard document, chapter §6.7, declaration,
A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:
— for an object, causes storage to be reserved for that object;
— .....
When you put extern storage class specifier, you're declaring a variable, not defining it.
So, you need to define the variable before you use it.
Add
volatile unsigned int C1TX0PRIO;
in your source file.

Declare function as non-static and implement as static inline

I want to write different implementations for my function, some inline and some not. Thus, I want to declare the function as:
// MyHeader.h
int myFunc(void);
#if DO_INLINE
static inline int myFunc(void) { return 42; }
#endif
And then also have:
// MySource.c
#if !DO_INLINE
#include "myHeader.h"
int myFunc(void) { return 42; }
#endif
I'll specify DO_INLINE at compile time.
MSVC has no problems with this, but GCC (4.1.1) complains that I'm declaring a static function after I've already declared it as non-static. If I remove the static qualifier, and #include "MyHeader.h" from more than one compilation unit, it will complain about multiple definitions. (As if the inline functions are extern.) I don't quite understand why the compiler has problems with this.
I think this should be pretty obvious and unambiguous:
int myFunc(void);
static inline int myFunc(void) { return 42; }
It shouldn't require the declaration to be static.
That said, there is a solution to my problem that I'm trying very hard to avoid:
#if DO_INLINE
#define MAYBE_STATIC static
#else
#define MAYBE_STATIC
#endif
MAYBE_STATIC int myFunc(void);
EDIT: Here is a more realistic use case for this: http://codepad.org/OkC0Su3v
This header.h should work:
// MyHeader.h
#if DO_INLINE
static inline int myFunc(void) { return 42; }
#else
int myFunc(void);
#endif
Figured it out closely enough. The implementation should be defined as "extern inline" instead:
// MyHeader.h
int myFunc(void);
#if DO_INLINE
extern inline int myFunc(void) { return 42; }
#endif
The compiler will inline this function where it sees fit, but still compile it once as a function, to make it available for linking. That part I don't need, but it doesn't really hurt.

extern without type

If the syntax of extern is
extern <type> <name>;
how do I extern if I have an unnamed, single use struct:
struct {
char **plymouthThemes;
char *plymouthTheme;
} global;
I've tried
extern global;
without any type, and it doesn't work.
Or, do I have to name the struct?
You need to name your struct and put it in a .h file or included the definition by hand in every source file that uses global. Like this
///glob.h
struct GlobalStruct
{
///char** ...
///
};
///glob.cpp
#include "glob.h"
struct GlobalStruct global;
///someOtherFile.cpp
#include "glob.h"
extern struct GlobalStruct global;
If you do not want to name a struct there's common method:
--- global.h: (file with global struct definition):
#ifdef GLOBAL_HERE /* some macro, which defined in one file only*/
#define GLOBAL
#else
#define GLOBAL extern
#endif
GLOBAL struct {
char **plymouthThemes;
char *plymouthTheme;
} global;
---- file1.c (file where you want to have global allocated)
#define GLOBAL_HERE
#include "global.h"
---- file2.c (any oher file referencing to global)
#include "global.h"
The macro GLOBAL is conditionally defined so its usage will prepend a definition with "extern" everywhere except source where GLOBAL_HERE is defined. When you define GLOBAL_HERE then variable gets non-extern, so it will be allocated in output object of this source.
There's also short trick definition (which set in single .c file where you allocate globals):
#define extern
which cause preprocessor to remove extern (replace with empty string). But do not do it: redefining standard keywords is bad.
The idea is that you need to declare only one but still need to define the variable in each other file that uses it. The definition includes both the type (in your case a header define structure - which therefore need include) and the extern keyword to let know the compiler the declaration is in a different file.
here is my example
ext.h
struct mystruct{
int s,r;
};
ext1.c
#include "ext.h"
struct mystruct aaaa;
main(){
return 0;
}
ext2.c
#include "ext.h"
extern struct mystruct aaaa;
void foo(){
aaaa;
}
ext3.c
#include "ext.h"
extern struct mystruct aaaa;
void foo2(){
aaaa;
}

shared global variables in C

How can I create global variables that are shared in C? If I put it in a header file, then the linker complains that the variables are already defined. Is the only way to declare the variable in one of my C files and to manually put in externs at the top of all the other C files that want to use it? That sounds not ideal.
In one header file (shared.h):
extern int this_is_global;
In every file that you want to use this global symbol, include header containing the extern declaration:
#include "shared.h"
To avoid multiple linker definitions, just one declaration of your global symbol must be present across your compilation units (e.g: shared.cpp) :
/* shared.cpp */
#include "shared.h"
int this_is_global;
In the header file write it with extern.
And at the global scope of one of the c files declare it without extern.
In the header file
header file
#ifndef SHAREFILE_INCLUDED
#define SHAREFILE_INCLUDED
#ifdef MAIN_FILE
int global;
#else
extern int global;
#endif
#endif
In the file with the file you want the global to live:
#define MAIN_FILE
#include "share.h"
In the other files that need the extern version:
#include "share.h"
You put the declaration in a header file, e.g.
extern int my_global;
In one of your .c files you define it at global scope.
int my_global;
Every .c file that wants access to my_global includes the header file with the extern in.
If you're sharing code between C and C++, remember to add the following to the shared.hfile:
#ifdef __cplusplus
extern "C" {
#endif
extern int my_global;
/* other extern declarations ... */
#ifdef __cplusplus
}
#endif
There is a cleaner way with just one header file so it is simpler to maintain.
In the header with the global variables prefix each declaration with a keyword (I use common) then in just one source file include it like this
#define common
#include "globals.h"
#undef common
and any other source files like this
#define common extern
#include "globals.h"
#undef common
Just make sure you don't initialise any of the variables in the globals.h file or the linker will still complain as an initialised variable is not treated as external even with the extern keyword. The global.h file looks similar to this
#pragma once
common int globala;
common int globalb;
etc.
seems to work for any type of declaration. Don't use the common keyword on #define of course.
There is a more elegant way to create global variables.
Just declare the variables as static inside a ".c" source file and create set/get functions.
The example below I use to override malloc, realloc and free functions during memory allocation tests.
Example:
memory-allocator.h
#ifndef MEMORY_ALLOCATOR_H_
#define MEMORY_ALLOCATOR_H_
#include <stddef.h>
void std_set_memory_allocators(void *(*malloc)(size_t size),
void *(realloc)(void *ptr, size_t size),
void (*free)(void *ptr));
void std_set_reset_allocators();
void *std_malloc(size_t size);
void *std_realloc(void *ptr, size_t size);
void std_free(void *ptr);
#endif // MEMORY_ALLOCATOR_H_
memory-allocator.c
#include "memory-allocator.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
void *(*malloc)(size_t size);
void *(*realloc)(void *ptr, size_t size);
void (*free)(void *ptr);
} StdMemoryAllocator;
StdMemoryAllocator memory_allocators = {&malloc, &realloc, &free};
void std_set_memory_allocators(void *(*malloc)(size_t size),
void *(realloc)(void *ptr, size_t size),
void (*free)(void *ptr)) {
memory_allocators.malloc = malloc;
memory_allocators.realloc = realloc;
memory_allocators.free = free;
}
void std_set_reset_allocators() {
memory_allocators.malloc = malloc;
memory_allocators.realloc = realloc;
memory_allocators.free = free;
}
void *std_malloc(size_t size) {
return memory_allocators.malloc(size);
}
void *std_realloc(void *ptr, size_t size) {
return memory_allocators.realloc(ptr, size);
}
void std_free(void *ptr) {
memory_allocators.free(ptr);
}
The struct static struct StdMemoryAllocator_s memory_allocators is started automatically when the application starts, and it point to the default C memory allocators.

Resources