1. Static
(1) First to introduce its first and most important one: hidden.
When we compile multiple files at the same time, all global variables and functions that do not have a static prefix have global visibility. For the understanding of this sentence, I would say for example. We want to compile two source files at the same time, one is A.C and the other is main.c.
Here's what a.c.
[CPP]View Plaincopy
- Char A = ' A ' ; //global variable
- void msg ()
- {
- printf ("hello/n");
- }
Here's what main.c .
[CPP]View Plaincopy
- int main ( span class= "keyword" >void )
- {
- extern char a; // extern variable must be declared before use
- printf ( , a);
- (void ) msg ( );
- return 0;
- }
The running result of the program is:
A Hello
You might ask: Why are global variables A and function msg defined in A.C used in MAIN.C? As mentioned earlier, all global variables and functions that do not have a static prefix have global visibility and other source files can be accessed. In this example, a is a global variable, MSG is a function, and neither has a static prefix, so MAIN.C is visible for additional source files.
If static is added, it is hidden from other source files. For example, before the definition of a and MSG, add STATIC,MAIN.C to see them. With this feature, you can define a function with the same name and a variable of the same name in different files without worrying about naming conflicts. Static can be used as a prefix for functions and variables, and for functions, static is limited to hiding, and for variables, static has the following two functions.
(2) The second function of static is to keep the contents of a variable persistent. Variables stored in the static data area are initialized at the start of the program and are the only one initialized. A total of two variables are stored in static storage: Global variables and static variables, except that, compared to global variables, static can control the visible range of variables, in the final analysis, static is used to hide them. Although this usage is not common, I would like to cite an example.
[CPP]View Plaincopy
- #include <stdio.h>
- int Fun (void) {
- Static int count = 10; //In fact this assignment statement has never been executed
- return count--;
- }
- int count = 1;
- int Main (void)
- {
- printf ("global/t/tlocal static/n");
- for (; count <=; ++count)
- printf ("%d/t/t%d/n", Count, Fun ());
- return 0;
- }
The running result of the program is:
Global local static
1 10
2 9
3 8
4 7
5 6
6 5
7 4
8 3
9 2
10 1
(3) The third function ofstatic is initialized to 0by default. In fact, global variables also have this property, because global variables are also stored in the static data area. In the static data area, all bytes in memory default values are 0x00, sometimes this feature can reduce the workload of the programmer. For example, to initialize a sparse matrix, we can place all the elements in one place 0, and then assign values to elements that are not 0 . If it is defined as static, it eliminates the first 0 operation. Another example is to put a character array as a string to use, but also feel each time at the end of the character array to add '/0 ' too much trouble. If the string is defined as static, it saves the trouble because it is '/0 '. 2 InlineLet's look at the following function, where there is only one line in the function body:
Double Average (double total, int number) {
return total/number;
}
Is it necessary to define such a simple function? In fact, it has some advantages: first, it makes the program more readable, and second, it makes the code reusable. However, it also has drawbacks: when it is frequently called, there is a loss in the performance of the application (time + space efficiency, especially time here) due to the overhead of calling the function. For example, average repeatedly calls thousands of times in a looping statement, reducing the execution efficiency of the program.
So, is there a way to avoid the overhead of function calls? For the above function, I can define it as the form of an inline function:
Inline double Average (double total, int number) {
return total/number;
}
The introduction of functions can reduce the program's target code and realize the sharing of program code.
function calls require time and space overhead, and the calling function actually transfers the program execution process to the called function, after the code of the function is executed, and then back to the place where it was called. This call operation requires the protection of the scene before the call and memory of the execution of the address, returned to resume the scene, and the original saved address to continue execution. This overhead can be negligible for longer functions, but for functions that are short and frequently called by function body Code, this overhead cannot be overlooked. The introduction of inline functions is to solve this problem and improve the running efficiency of the program.
At the time of program compilation, the compiler replaces the call expression for an inline function that appears in the program with the function body of an inline function. Because the code in the inline function body is replaced in the program at compile time, it increases the amount of code in the target program, which in turn increases the space overhead, which is not as large as a function call in time overhead, and can be seen in exchange for time savings at the expense of increasing the target code.
Summary: The inline function is more efficient at running time, but it increases the space overhead.
That is, the inline function is intended to improve the execution efficiency (speed) of the function.
Non-inline function calls have the overhead of stack memory creation and deallocation
In C can be used to improve the efficiency of the implementation of macro code, macro code is not a function but the use of functions like a function, the compiler used to copy the macro code to replace the function call, save the parameter stack, generate assembly language call calls, return parameters, execute return, etc., thereby improving the speed.
Disadvantages of Using Macros: (1) error prone (preprocessor often produces unexpected marginal effects when copying macro code)
For example: #define MAX (a) (a) > (b)? (a): (b)
Statement result = MAX (I,J) + 2 is extended to result = (i) > (j)? (i):(j) +2;
But the meaning is result = ((i) > (j)? ( i):(j)) + 2;
(2) cannot be debugged
(3) Unable to manipulate private data members of class
C + + function inline mechanism not only has the efficiency of macro code, but also increases the security, and can manipulate the data members of the class freely.
The keyword inline must be placed with the function definition body in order for the function to be truly inline, and only the inline is placed in front of the function declaration. Because Inlin is a keyword for implementation, it is not a keyword for declarations.
Many books add the inline keyword to the declaration and definition of an inline function, but should not be added before the declaration (plus does not affect function functionality), because declarations and definitions cannot be confused.
★ Declarations, definitions and statements
Statement: is to introduce a name to the system (a name is a block of memory alias), just tell the compiler the name of the value of the type and declare the existence of the name, only that.
Definition: The allocation of storage space, that is, the storage type.
Statement: The basic component of a program, with executable statements (defined Yes) and non-enforceable statements (declarations are).
Some global variables or local variables defined before formal programming statements are declared in C and defined in C + +.
For example: int a;//is declared in the subscript C, is a non-executable statement, and is defined in C + + as an executable statement
extern int a;//is declared, is a non-executable statement CWinApp curapp;//object definition is an executable statement
There are several issues to be aware of when using inline functions:
(1) inline functions defined in one file cannot be used in another file. They are usually shared in the header file.
(2) The inline function should be concise, only a few statements, if the statement is more, not suitable for the definition of inline functions.
(3) in the inline function body, there cannot be a loop statement, an if statement, or a switch statement, otherwise the compiler will treat the function as a non-inline function, even if there is an inline keyword.
(4) The inline function is declared before the function is called.
For example:
#include <iostream.h>
int increment (int i);
inline int increment (int i) {
i++; return i;
}
void Main (void) {...
}
If we modify the program, move the definition of the inline function after main ():
#include <iostream.h>
int increment (int i);
void Main (void) {...
}
The inline function definition is placed after the main () function
inline int increment (int i) {
i++; return i;
}
The inline function is not defined until it is called, and the compiler does not replace it directly in main when it is compiled. In other words, "increment (int i)" is called only as a normal function and does not have the nature of the inline function, which can not improve the operation efficiency.
3 volatile
The volatile reminder compiler can change the variables that are defined later, so the compiled program reads the data directly from the variable address each time it needs to store or read the variable. Without the volatile keyword, the compiler might optimize reading and storage, may temporarily use the value in the register, and if the variable was updated by another program, there would be an inconsistency. The following examples illustrate. In DSP development, it is often necessary to wait for an event to be triggered, so the program is often written like this:
Short flag;
void Test ()
{
Do1 ();
while (flag==0);
Do2 ();
This program waits for the value of the memory variable flag to change to 1 (suspect here is 0, a little doubt) before running Do2 (). The value of the variable flag is changed by another program, which may be a hardware interrupt service program. For example, if a button is pressed, the DSP will be interrupted, the key in the interrupt program to modify flag 1, so that the above program can continue to run. However, the compiler does not know that the value of flag will be modified by another program, so when it is optimized, the value of flag may be read into a register first, and then wait for that register to become 1. If such optimizations are unfortunate, then the while loop becomes a dead loop because the contents of the register cannot be modified by the Interrupt service program. In order for the program to read the value of the TRUE flag variable every time, it needs to be defined as follows:
volatile short flag;
It is important to note that there may be no volatile or normal operation, but it is possible to modify the compiler's optimization level and not run properly. As a result, the debug version is normal, but the release version is not a normal issue. So for security reasons, just wait for another program to modify a variable, plus the volatile keyword.
Volatile is meant to be "variable."
Because the access register is faster than RAM, the compiler generally makes optimizations to reduce access to external RAM. Like what:
static int i=0;
int main (void)
{
...
while (1)
{
if (i) do_something ();
}
}
/* Interrupt Service routine. */
void isr_2 (void)
{
I=1;
}
The intent of the program is to call the Do_something function in main when the isr_2 interrupt is generated, but because the compiler determines that I is not modified in the main function, it may only perform a single read from I to a register. Then each time the if judgment uses only the "I copy" inside the register, causing the do_something to never be called. If you add a volatile modifier to a variable, the compiler guarantees that read and write operations on this variable will not be optimized (definitely executed). I should also explain this in this example.
Generally, volatile is used in several places:
1, the change in the Interrupt service program for other programs to detect variables need to add volatile;
2, multi-tasking environment to share the logo should be added volatile;
3, Memory mapping hardware register usually also add volatile description, because each time it read and write may be different meanings;
In addition, these situations often have to consider the integrity of the data at the same time (the correlation of several signs read half interrupted rewrite), in 1 can be achieved by the shutdown interrupt, 2 can prohibit task scheduling, 3 of the hardware can only rely on good design.
The meaning of volatile
Volatile is always related to optimization, the compiler has a technique called data flow analysis, where variables in the parser are assigned, where they are used, where they are invalidated, analysis results can be used for constant merging, constant propagation and other optimizations, and further death code can be eliminated. But sometimes these optimizations are not required by the program, you can use the volatile keyword to prohibit these optimizations, the literal meaning of volatile is variable, it has the following role:
1 The volatile variable is not cached in a register between two operations. In multi-tasking, interrupts, and even setjmp environments, variables can be changed by other programs, and the compiler cannot know for sure, and volatile is telling the compiler this is the case.
2 Do not do constant merging, constant propagation and other optimizations, so like the following code:
volatile int i = 1;
if (i > 0) ...
The IF condition is not treated as unconditional true.
3 reading and writing to volatile variables is not optimized. If you assign a value to a variable but it doesn't work, the compiler can often omit that assignment, but the processing of memory Mapped IO cannot be optimized.
Some people said that volatile can guarantee the atomic nature of memory operations, this is not accurate, one, x86 need lock prefix to ensure atomicity under the SMP, and second, RISC can not directly operate on the memory, to ensure that the atomicity of other methods, such as Atomic_inc.
For Jiffies, it has been declared as a volatile variable, and I think it is possible to use jiffies++ directly, and there is no need to use that complex form, because that does not guarantee atomicity.
You may not know that in Pentium and subsequent CPUs, the following two sets of instructions
Inc jiffies
;;
mov jiffies,%eax
Inc%eax
mov%eax, jiffies
function the same, but an instruction is not as fast as three instructions.
The role of static inline volatile