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;
}
Related
I'm trying to define a structure as a typedef in a header file and use it in many sources. I found a similar answer in here but I'm not sure if a typedef can be defined as extern. Also msg_encoded should have a default value.
// lib.h
#ifndef lib_h
#define lib_h
struct msg_encoded_s
{
uint8_t msg[10];
int length;
} msg_encoded_default = {{0}, 0};
typedef struct msg_encoded_s msg_encoded;
#endif
// lib.c
#include "lib.h"
msg_encoded some_var;
// main.c
# include "lib.h"
int main(){
msg_encoded some_other_var;
}
main.o:(.bss.msg_encoded_default+0x0): multiple definition of
`msg_encoded_default'
A "declaration" like
struct msg_encoded_s {
...
} msg_encoded_default;
is actually both (1) a definition of a struct-type named msg_encoded_s and (2) the definition of a variable of this type named `msg_encoded_default.
Hence, if you include this header file in separate translation units, then you will redefine a variable named msg_encoded_default, which is not allowed.
To overcome this, write a header like...
typedef struct msg_encoded_s
{
uint8_t msg[10];
int length;
} msg_encoded;
extern msg_encoded msg_encoded_default;
An in exactly one translation unit write:
#include "myheader.h"
msg_encoded msg_encoded_default = {{0}, 0};
In all other translation units just write...
#include "myheader.h"
...
int test = msg_encoded_default.length; // or something like this
I am building a project that I am trying to organize as follows:
main.c
globals.h
structures.h
FunctionSet1.c, FunctionSet1.h
FunctionSet2.c, FunctionSet2.h
etc.
I thought I could define a structure type in structures.h:
struct type_struct1 {int a,b;}; // define type 'struct type_struct1'
then declare a function1() returning a structure of type type_struct1 in FunctionSet1.h:
#include "structures.h"
struct type_struct1 function1(); // declare function1() that returns a type 'struct type_struct1'
then write function1() in FunctionSet1.c:
#include "FunctionSet1.h"
struct type_struct1 function1() {
struct type_struct1 struct1; // declare struct1 as type 'struct type_struct1'
struct1.a=1;
struct1.b=2;
return struct1;
}
Edit: with the corrected code above, the compiler returns
306 'struct' tag redefined 'type_struct1' structures.h
Is the file set good practice ?
What is the good practice to manage the structures ?
In your example, you declare a structure named type_struct in structure.h, then in FunctionSet1.h the structure that you are returning is type_struct, and in the .c it is called struct1.
So i think that the problem is that struct1 and type_struct are not recognized because they have never been defined ...
However, the organization of your files is fine.
Your general structure looks good. One thing you need to do, as zenith mentioned, is to put include guards into your header files. What that is is a set of #define's that make sure that the contents of the header are not included more that once in a given file. For example:
structures.h:
#ifndef STRUCTURES_H
#define STRUCTURES_H
struct type_struct1{
int a,b;
};
...
// more structs
...
#endif
FunctionSet1.h:
#ifndef FUNCTION_SET_1_H
#define FUNCTION_SET_1_H
#include "structures.h"
struct type_struct1 function1();
...
// more functions in FucntionSet1.c
...
#endif
main.c:
#inlcude <stdio.h>
#include "structures.h"
#include "FunctionSet1.h"
int main(void)
{
struct type_struct1 struct1;
struct1 = function1();
return 0;
}
Here, main.c includes structures.h and FunctionSet1.h, but FunctionSet1.h also includes structures.h. Without the include guards, the contents of structures.h would appear twice in the resulting file after the preprocesser is done. This is probably why you're getting the "tag redefined" error.
The include guards prevent these type of errors from happening. Then you don't have to worry about whether or not a particular header file was included or not. This is particularly important if you're writing a library, where other users may not know the relationship between your header files.
First of all, you have to declare the structure in your file.h (you can use typedef to create an alias)
typedef struct Books
{
char title[50];
int book_id;
} books;
then, you have to include your file.h in your file.c and declare your variable like this
#include "file.h"
int main()
{
books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
or like this if you didn't use typedef
#include "file.h"
int main()
{
struct Books book1;
book1.title = "Harry Potter";
book1.book_id = 54;
}
Thank you all.
I read again what you said and found that the code above is now correct.
The error I report is with testing the following main.c
#include "structures.h"
#include "FunctionSet1.h"
void main() {
struct type_struct1 struct2;
struct2=function1();
}
in which structures.h is included again, thus causing the error. Removing the include eliminates the error.
I will now look into header guards to avoid such problems.
Thanks again.
Say I have 3 files: file1.c, file2.c and globals.h. file1.c and file2.c both include globals.h. file1.c contains a struct that file2.c needs to use. Is it better to make the struct itself extern or create a pointer to the struct and make that pointer extern in globals.h?
If I understand correctly and your "a struct" is supposed to be a global object (which is a questionable design choice), then I'd do it like this:
foo.h:
typedef struct foo_struct
{
/* ... */
} foo;
extern foo the_foo;
foo.c: [If you like and if it makes sense, you can merge this into file1.c.]
#include "foo.h"
foo the_foo = { /* ... */ };
file1.c and file2.c:
#include "foo.h"
#include "global.h"
/* ... */
I am using Linux as my programming platform and C language as my programming language.
My problem is, I define a structure in my main source file( main.c):
struct test_st
{
int state;
int status;
};
So I want this structure to use in my other source file(e.g. othersrc.). Is it possible to use this structure in another source file without putting this structure in a header?
You can define the struct in each source file, then declare the instance variable once as a global, and once as an extern:
// File1.c
struct test_st
{
int state;
int status;
};
struct test_st g_test;
// File2.c
struct test_st
{
int state;
int status;
};
extern struct test_st g_test;
The linker will then do the magic, both source file will point to the same variable.
However, duplicating a definition in multiple source files is a bad coding practice, because in case of changes you have to manually change each definition.
The easy solution is to put the definition in an header file, and then include it in all the source file that use the structure. To access the same instance of the struct across the source files, you can still use the extern method.
// Definition.h
struct test_st
{
int state;
int status;
};
// File1.c
#include "Definition.h"
struct test_st g_test;
// File2.c
#include "Definition.h"
extern struct test_st g_test;
You can use pointers to it in othersrc.c without including it:
othersrc.c:
struct foo
{
struct test_st *p;
};
but otherwise you need to somehow include the structure definition. A good way is to define it in main.h, and include that in both .c files.
main.h:
struct test_st
{
int state;
int status;
};
main.c:
#include "main.h"
othersrc.c:
#include "main.h"
Of course, you can probably find a better name than main.h
// use a header file. It's the right thing to do. Why not learn correctly?
//in a "defines.h" file:
//----------------------
typedef struct
{
int state;
int status;
} TEST_ST;
//in your main.cpp file:
//----------------------
#include "defines.h"
TEST_ST test_st;
test_st.state = 1;
test_st.status = 2;
//in your other.ccp file:
#include "defines.h"
extern TEST_ST test_st;
printf ("Struct == %d, %d\n", test_st.state, test_st.status);
Putting it in a header file is the normal, correct way to declare types shared between source files.
Barring that, you can treat main.c as a header file and include it in the other file, then only compile the other file. Or you can declare the same struct in both files and leave a note to yourself to change it in both places.
C supports separate compilation.
Put the structure declaration in a header file and #include "..." it in the source files.
It is perfectly reasonable to be inclusive with structs by leaving them in the source file instead. This is encapsulation. However if you're going to redefine struct multiple times in multiple source files then you might as well define the struct once in a header file instead and include that file as necessary.
Header file /* include this header file in both file1.c and file2.c
struct a {
};
struct b {
};
so header file included the declaration of both structures .
file 1.c
struct a xyz[10]; --> struct a defined here
to use struct b here in this file
extern struct b abc[20];
/* now can use in this file */
file2.c
struct b abc[20]; /* defined here */
to use struct a defined in file1.c
use extern struct a xyz[10]
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.