Declaration and definition of global variables based on C++

  • 2020-04-02 01:05:39
  • OfStack

(1) compilation unit (module)
After writing the code on VC or VS and clicking the compile button to generate the exe file, the compiler does two steps:
The first step is to compile each. CPP (. C) and corresponding. H file into an obj file.
The second step is to LINK all the obj files in the project and generate the final.exe file.
There are, then, two places where errors can occur:
One, compile-time errors, which are mostly syntax errors;
One, an error in linking, mainly by repeatedly defining variables, etc.
A compilation unit is each obj file that is generated during compilation.
An obj file is a compilation unit.
A. CPP (. C) and its corresponding. H file together form a compilation unit.
A project consists of many compilation units, each obj file containing the relative address of the variable store, etc.
(2) declaration and definition
When a function or variable is declared, it is not given the actual physical memory space.
When a function or variable is defined, it has actual physical space in memory.

If the external variable you refer to in the compilation unit is not defined anywhere in the project, then even if it passes at compile time, it will report an error at connection time because the program cannot find the variable in memory.
A function or variable can be declared many times, but a definition can only be made once.
(3) extern function
Role a:
When used with "C", extern "C" void fun(int a, int b); When compiling the name of the function fun, the compiler translates the corresponding function name according to the rules of C instead of C++.
Part two: When it is not used with "C" to modify a variable or function, as in the header file, extern int g_nNum; , which declares the scope of a function or variable whose declared functions and variables can be used in this or other compilation unit.
Namely B compilation unit to reference A compilation unit defined in the global variables, or functions, B compilation unit can be as long as the header file contains A compilation unit, in the compile phase, B compilation unit, although can't find this function or variable, but it won't be an error, it will be in A link from A compilation unit generated object code found in this function.
(4) global variable (extern)
There are two classes that need to use common variables, which we define as global variables. For example, res.h and res.cpp declare and define global variables, respectively, and the classes ProducerThread and ConsumerThread use global variables. (the following is the QT project code)

  
#pragma once  

#include <QSemaphore>  

const int g_nDataSize = 1000; //The total number of goods produced by the producer
const int g_nBufferSize = 500; //Size of ring buffer & NBSP;

extern char g_szBuffer[]; //Ring buffer & NBSP;
extern QSemaphore g_qsemFreeBytes; //Control the free area of the ring buffer (the area where the producer has not filled the data, or the area where the consumer has read it)
extern QSemaphore g_qsemUsedBytes; //Controls the usage area in the ring buffer (the area where the producer has filled the data, but the consumer has not read it) & NBSP;
  

In the above code, g_nDataSize, g_nBufferSize are global constants, and the others are global variables.

  
#pragma once  
#include "res.h"  

//Define the global variable & PI;
char g_szBuffer[g_nBufferSize];  
QSemaphore g_qsemFreeBytes(g_nBufferSize);  
QSemaphore g_qsemUsedBytes;  
  

When using global variables in other compilation units, you simply include the header file where they are located.

  
#include "consumerthread.h"  
#include "res.h"  
#include <QDebug>  
ConsumerThread::ConsumerThread(QObject* parent)  
: QThread(parent) {  
}  
ConsumerThread::ConsumerThread() {  

}  
ConsumerThread::~ConsumerThread() {  
}  
void ConsumerThread::run() {  
 for (int i = 0; i < g_nDataSize; i++) {  
  g_qsemUsedBytes.acquire();
  qDebug()<<"Consumer "<<g_szBuffer[i % g_nBufferSize];  
  g_szBuffer[i % g_nBufferSize] = ' ';  
  g_qsemFreeBytes.release();  
 }  
 qDebug()<<"&&Consumer Over";  
}  
  

You can also put the declaration and definition of a global variable together to prevent you from forgetting the definition, as shown above: extern char g_szBuffer[g_nBufferSize]; Then replace #include "res.h" in the file that references it with extern char g_szBuffer[]; .
But this is bad because you can't use #include "res.h" (with this, if you do it twice or more, you get a redefinition error; Note: Even in res. Add # pragma h once, or # # ifndef will appear to repeat definition, because each compilation unit is separate, will be on its own definition), then the res. Other functions or variables h statement, you also can't use, unless you are using extern decorate, so too much trouble, so it is recommended to use. H in the statement. The CPP defined in practice.
(5) static global variable (static)
Pay attention to use The static Modify variables, you can't use them extern To modify The static and extern You can't do it all at once.
The static Global variables are declared and defined at the same time, that is, when you use them in header files The static Global variables are declared and defined.
A global variable that is static can only be scoped to its own compilation unit. When other compilation units use it, they simply copy its value to other compilation units, and other compilation units will have a separate memory to save it, and changes made to it by other compilation units will not affect its value at the time of definition. That is, when other compilation unit A USES it, its physical address is not the same as when other compilation unit B USES it, and any changes made by A and B to it cannot be passed to each other.
Multiple references to the header file in which the static global variable resides do not result in a redefinition error because it is allocated extra space for storage in each compilation unit.
Here is the code sample for the Windows console application:

  
static char g_szBuffer[6] = "12345";  
void fun();  
  


  
#include "res.h"  
#include <iostream>  
using namespace std;  

void fun() {  
 for (int i = 0; i < 6; i++) {  
  g_szBuffer[i] = 'A' + i;  
 }  
 cout<<g_szBuffer<<endl;  
}  
  


  
void fun1();  
  


  
#include "test1.h"  
#include "res.h"  
#include <iostream>  
using namespace std;  

void fun1() {  
fun();  

 for (int i = 0; i < 6; i++) {  
  g_szBuffer[i] = 'a' + i;  
 }  
 cout<<g_szBuffer<<endl;  
}  
  


  
void fun2();  
  


  
#include "test2.h"  
#include "res.h"  
#include <iostream>  
using namespace std;  

void fun2() {  
 cout<<g_szBuffer<<endl;  
}  
  


  
#include "test1.h"  
#include "test2.h"  

int main() {  
 fun1();  
 fun2();  

 system("PAUSE");  
 return 0;  
}  
  

The operation results are as follows:


Our intuition is that the output of fun1() and fun2() is abcdef, but the output of fun2() is indeed the initial value. Then we followed up the debugging and found that the addresses of g_szBuffer in res, test1 and test2 are different, which are 0x0041a020, 0x0041a084 and 0x0041a040 respectively, which explains why they are different.
Note: when you define a static global variable, you usually put it in a. CPP file instead of an. H file, so that you don't pollute other compilation units unnecessarily.
(6) global constant (const)
When const is used on its own, it is the same as static (the address is different in each compilation unit, but since it is constant and cannot be changed, it doesn't matter much).
When const is used with extern, it has the same properties as extern.
[code]
Extern const char g_szBuffer [];           // write in. H  
Const char g_szBuffer[] = "123456"; // written into. CPP  
[/ code

Related articles: