I apologize for the volume of the answer (because of the examples), but it is understandable (I hope that it is clear) that I could not write more shortly.
Usually problems should not arise, although the use of external variables (constants) is a rather subtle point, especially for a mixture of modules (separate compilation) from C and C ++.
Linux example g ++ and gcc
Header file that is included in all modules:
#ifndef _EX_H #define _EX_H #include <stdint.h> extern int64_t v1; extern int8_t v2; extern const uint16_t cv3; #ifndef USEPLUSPLUS // with -DUSEPLUSPLUS g++ makes C++ function names (like _Z6ex_priPKc) in .o #ifdef __cplusplus extern "C" { #endif #endif void ex_pri (const char *title); void ex1 (void); void ex2 (void); #ifndef USEPLUSPLUS #ifdef __cplusplus } #endif #endif #ifdef __cplusplus #define COMP "g++" #else #define COMP "gcc" #endif #endif
#ifdef
around prototypes are needed only if you plan to use a mixture of modules compiled by gcc (C) and g ++ (C ++).
Now 4 files with our functions:
avp@avp-xub11:hashcode$ more ex.c ex1.c ex2.c ex_pri.c | cat :::::::::::::: ex.c :::::::::::::: #include <stdio.h> #include "ex.h" int main () { printf("main (%s): cv3 = %hu\n", COMP, cv3); ex_pri("start"); v1 = v2 = 10; ex_pri("mid"); ex1(); ex2(); ex_pri("finish"); return puts("End") == EOF; } :::::::::::::: ex1.c :::::::::::::: #include <stdio.h> #include "ex.h" void ex1 () { printf("ex1 (%s): change v1 = %lld to cv3 / 2 + 1\n", COMP, v1); v1 = cv3 / 2 + 1; } :::::::::::::: ex2.c :::::::::::::: #include <stdio.h> #include "ex.h" void ex2 () { printf("ex2 (%s): change v2 = %d to cv3 / 2 + 1\n", COMP, v2); v2 = cv3 / 2 + 1; } :::::::::::::: ex_pri.c :::::::::::::: #ifdef __cplusplus #include <iostream> #endif #include <stdio.h> #include "ex.h" int64_t v1 = 777666555444333222LL; int8_t v2 = -127; const uint16_t cv3 = 0xABCD; void ex_pri (const char *title) { printf ("%s\nex_pri (%s): v1 = %lld v2 = %d cv3 = 0x%04x\n", title ? title : "", COMP, v1, v2, cv3); #ifdef __cplusplus std::cout << "++++\n"; #endif } avp@avp-xub11:hashcode$
in which, in every way, we manipulate external variables. By the way, pay attention: the definition of a variable (constant) should be one-time Here are all the definitions in the ex_pri.c
file.
And you can play with different compilation options.
avp@avp-xub11:hashcode$ gcc -c ex1.c ex2.c ex_pri.c avp@avp-xub11:hashcode$ g++ ex.c ex1.o ex2.o ex_pri.o avp@avp-xub11:hashcode$ ./a.out main (g++): cv3 = 43981 start ex_pri (gcc): v1 = 777666555444333222 v2 = -127 cv3 = 0xabcd mid ex_pri (gcc): v1 = 10 v2 = 10 cv3 = 0xabcd ex1 (gcc): change v1 = 10 to cv3 / 2 + 1 ex2 (gcc): change v2 = 10 to cv3 / 2 + 1 finish ex_pri (gcc): v1 = 21991 v2 = -25 cv3 = 0xabcd End avp@avp-xub11:hashcode$ nm ex_pri.o 00000000 R cv3 00000000 T ex_pri U printf 00000000 D v1 00000008 D v2 avp@avp-xub11:hashcode$ g++ -c ex1.c ex2.c ex_pri.c avp@avp-xub11:hashcode$ g++ ex.c ex1.o ex2.o ex_pri.o avp@avp-xub11:hashcode$ ./a.out main (g++): cv3 = 43981 start ex_pri (g++): v1 = 777666555444333222 v2 = -127 cv3 = 0xabcd ++++ mid ex_pri (g++): v1 = 10 v2 = 10 cv3 = 0xabcd ++++ ex1 (g++): change v1 = 10 to cv3 / 2 + 1 ex2 (g++): change v2 = 10 to cv3 / 2 + 1 finish ex_pri (g++): v1 = 21991 v2 = -25 cv3 = 0xabcd ++++ End avp@avp-xub11:hashcode$ g++ -c ex1.c ex2.c ex_pri.c -DUSEPLUSPLUS avp@avp-xub11:hashcode$ nm ex_pri.o 00000000 R cv3 U __cxa_atexit U __dso_handle 000000b1 t _GLOBAL__sub_I_v1 U printf 00000000 D v1 00000008 D v2 00000072 t _Z41__static_initialization_and_destruction_0ii 00000000 T _Z6ex_priPKc U _ZNSt8ios_base4InitC1Ev U _ZNSt8ios_base4InitD1Ev U _ZSt4cout 00000000 b _ZStL8__ioinit U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc avp@avp-xub11:hashcode$ g++ ex.c ex1.o ex2.o ex_pri.o /tmp/ccp5Fn5P.o: In function `main': ex.c:(.text+0x33): undefined reference to `ex_pri' ex.c:(.text+0x5a): undefined reference to `ex_pri' ex.c:(.text+0x5f): undefined reference to `ex1' ex.c:(.text+0x64): undefined reference to `ex2' ex.c:(.text+0x70): undefined reference to `ex_pri' collect2: error: ld returned 1 exit status
You see, here the compiler (g ++) expects the names of functions in the “sishny” format, and we have already done .o
with C ++ function names (this is defined by extern "C" ...
in the header file). Therefore, we call:
avp@avp-xub11:hashcode$ g++ ex.c ex1.o ex2.o ex_pri.o -DUSEPLUSPLUS avp@avp-xub11:hashcode$ ./a.out main (g++): cv3 = 43981 start ex_pri (g++): v1 = 777666555444333222 v2 = -127 cv3 = 0xabcd ++++ mid ex_pri (g++): v1 = 10 v2 = 10 cv3 = 0xabcd ++++ ex1 (g++): change v1 = 10 to cv3 / 2 + 1 ex2 (g++): change v2 = 10 to cv3 / 2 + 1 finish ex_pri (g++): v1 = 21991 v2 = -25 cv3 = 0xabcd ++++ End avp@avp-xub11:hashcode$
Well, and so on.