2010-10-18 wcdj
This article is followed:Dissection C Chapter 1_2
Http://blog.csdn.net/delphiwcdj/archive/2010/10/06/5924226.aspx
[1] How many keywords does C have? How to Use sizeof? Is it a function?
[2] what is definition? What is declaration? What are their differences?
[3] Analysis of keyword roles one by one
(1) Auto
(2) Register
(3) static
(4) Basic Data Types
(5) sizeof
(6) signed, unsigned
(7) If, else
(8) switch, Case
(9) do, while,
(10) GOTO
(11) void
(12) Return
(13) const
(14) Volatile
(15) extern
(16) struct
(17) Union
(18) Enum
(19) typedef
(13) const
Const is the abbreviation of constant, which means constant, also translated as constant, constant, etc.
Note]
[1] Many people think that the value modified by const is a constant. This is not accurate. To be precise, it should be: Read-Only variables whose values cannot be used during compilation because the compiler does not know the stored content during compilation.
# Include <cstdio> <br/> int main () <br/> {<br/> const int max = 100; <br/> int A [Max] = {0}; <br/> return 0; <br/>}< br/>
Is this correct? Max is a read-only variable and its value cannot be used during compilation. (C is incorrect. c ++ is acceptable)
[2] The purpose of const is to replace precompiled commands, eliminate its disadvantages, and inherit its advantages. Note that define is not a keyword.
PS: refer to the detailed introduction to one of the terms in essential C ++.
[3] Read-Only variables modified by const must be initialized at the same time as defined.
[4] Can I use the read-only variable modified by const after the case statement? (Of course)
# Include <cstdio> <br/> int main () <br/> {<br/> const int I _am_const = 100; <br/> switch (I _am_const) <br/>{< br/> case 1: <br/> break; <br/> case 2: <br/> break; <br/> case 100: <br/> printf ("OK/N"); <br/> break; <br/> default: <br/> NULL; <br/>}< br/> return 0; <br/>}
[5] saves space, avoids unnecessary memory allocation, and improves efficiency.
The compiler is generally not normal (Global ?) The const Read-Only variables are allocated to the bucket, but are saved in the symbol table, which makes it a value during compilation without the operation of storage and read memory, this makes it highly efficient.
The read-only variables defined by const only provide the corresponding memory address from the assembly point of view, rather than the number of immediate values like # define. Therefore, the read-only variables defined by const have only one copy during the program running (because they are global read-only variables and are stored in the static zone ), # The macro constant defined by define has several copies in the memory. # The define macro is replaced during the pre-compilation phase, while the read-only variable modified by const is determined during compilation. # The define macro has no type, while the read-only variable modified by const has a specific type.
To verify the above discussion, I did the following test:
# Include <cstdio> <br/> # define m 3 // macro constant <br/> const int n = 100; // n is not put into memory at this time <br/> int g_val = 1; <br/> int main () <br/>{< br/> 0042d600 push EBP <br/> 0042d601 mov EBP, esp <br/> 0042d603 sub ESP, 0f0h <br/> 0042d609 push EBX <br/> 0042d60a push ESI <br/> 0042d60b push EDI <br/> 0042d60c Lea EDI, [ebp-0F0h] <br/> 0042d612 mov ECx, 3ch <br/> 0042d617 mov eax, 0 cccccccch <br/> 0042d61c rep STOs dword ptr es: [EDI] <br/> // const int n = 100; // n is not put into memory at this time <br/> int A = N; // memory is allocated to N at this time and will not be allocated in the future <br/> 0042d61e mov dword ptr [a], 64 h <br/> int B = m; // macro replacement during pre-compilation and memory allocation <br/> 0042d625 mov dword ptr [B], 3 <br/> int c = N; // no memory allocation <br/> 0042d62c mov dword ptr [c], 64 h <br/> int d = m; // macro replacement, allocate memory again <br/> 0042d633 mov dword ptr [d], 3 <br/> return 0; <br/> 0042d63a XOR eax, eax <br/>}< br/> 0042d63c pop EDI <br/> 0042d63d pop ESI <br/> 0042d63e pop EBX <br/> 0042d63f mov ESP, EBP <br/> 0042d641 pop EBP <br/> 0042d1_ret
My question is:
(Use the const variable as the global and local)
When the const variable is global, the vs compiler does not allocate storage space for it, that is, it replaces it with the immediate number.
However, when the const variable is declared as a local variable, the vs compiler allocates space for it. In this case, is this "advantage" of const specific to global variables.
A post to discuss this issue:
Http://topic.csdn.net/u/20101013/16/bca742a9-b0c4-4d6b-b301-7d273db44c59.html
The final conclusion is:
: In debug, the compiler stores a large amount of data that is not required during running and is used for debugging information. So it is different from the release version. This issue has not yet been completely resolved. There is no good way to test and verify it. (If you know, please tell me THX)
[6] modify general variables.
Const int I = 2; <br/> // The above same as <br/> int const I = 2;
That is, the modifier const can be used before or after the type specifier. (Usually before the type specifier, but we recommend that you use it after the type specifier. For details, see section 4.2.5 In C ++ primer)
[7] modify the array.
Const int A [] = {1, 2, 3, 4, 5}; <br/> // same as <br/> int const A [] = {1, 2, 4, 5 }; <br/>
[8] modify the pointer.
Const int * P1; // P1 is variable, and the object to which P1 points is immutable <br/> int const * P2; // same as above <br/> int ival = 1; <br/> int * const P3 = & ival; // P3 is unchangeable and must be initialized. The object pointed to by P3 is variable <br/> const int * const P4 = & ival; // The objects pointed to by pointers P4 and P4 are unchangeable and P4 must be initialized.
Memory method 1
: The const modifier can be placed before or after the modifier type. It is recommended to be placed later. See section 4.2.5 In C ++ Primer
Memory method 2
: Ignore the type name first (the type name is ignored when the compiler parses). We can see which kind of const is close to, that is, the type next to it.
Const int
* P1; // const modifier * P1
Int
Const * P2; // same as above
Int ival = 1;
Int
* Const P3 = & ival; // const modifies p3
Const int
* Const P4 = & ival; // The first const modifier * P4, and the second const modifier p4
9. Modify the parameters of a function.
The const modifier can also be used to modify the function parameters. It is used when you do not want this parameter value to be accidentally changed by the function body.
Example: void fun (const int I );
Tells the compiler that I cannot be changed in the function body, thus preventing unintentional or incorrect modifications.
[10] modify the return value of a function.
The const modifier can also modify the return value of a function. The return value cannot be changed.
Example: const int fun ();
[11] const has been extended in C ++, and its features can be found for relevant information.
(14) Volatile
Volatile is variable and unstable. Many people have never seen this keyword, do not know its existence, or know its existence, but never used it.
Like const, the volatile keyword is a type modifier. Variables modified by volatile indicate that they can be changed by unknown factors in some compilers, such as operating systems, hardware, or other threads. When the variable declared by this keyword is encountered, the compiler no longer optimizes the code accessing the variable, so as to provide stable access to the special address.
Example:
Int I = 10;
Int J = I; // (1)
Int K = I; // (2)
At this time, the compiler optimizes the code because I is not used as the left value in the (1) and (2) statements. At this time, the compiler considers that the I value has not changed. Therefore, after the I value is obtained from the memory in the (1) Statement and assigned to J, this value is not lost, instead, this value is used to assign a value to K in the (2) statement. The compiler does not retrieve the I value from the memory again, which improves the efficiency. Note: (1), (2) the I between statements is not used as the left value.
Another example:
Volatile int I = 10;
Int J = I; // (3)
Int K = I; // (4)
The volatile keyword tells the compiler that I may change at any time. Each time you use it, you must retrieve the I value from the memory, therefore, the compilation code generated by the compiler will re-read data from the address of I and put it in K. In this case, if I is a register variable, a port data, or shared data of multiple threads, it is prone to errors. Therefore, volatile can ensure stable access to special addresses.
Note]
In vc6, the Code is not optimized in debug mode, so the function of this keyword may not be seen. We can generate both the debug and release programs for a test.
[Thinking] Is there a problem with the following code? If not, what is the attribute of I? (I is the const attribute)
Const volatile int I = 10;
I = 20;
(15) extern
Extern is external and external. Extern can be placed before a variable or function to identify the definition of a variable or function in another file. The following code uses these variables or functions as external, not defined in this file, prompt the compiler to find its definition in other modules when it encounters this variable and function.
[Question] What is the relationship between extern and header files?
(16) struct
Struct is a magic keyword. It packs associated data into a whole for ease of use.
In network protocols, communication control, embedded systems, and driver development, what we often want to transmit is not a simple byte stream (char array), but a combination of multiple types of data, it is a struct. Experienced developers often store all the content to be transmitted in the char array in sequence, and transmit network packets and other information through pointer offset (this method has been done by themselves, it seems really stupid now). This programming is complex and error-prone.
In this case, you only need a struct. At ordinary times, we require that the number of function parameters should be no more than four. If the number of function parameters is greater than four, it is very prone to errors (including the meaning and order of each parameter ), efficiency will also be reduced (related to the specific CPU, ARM chip is very careful about processing more than four parameters, please refer to the relevant information for details ). At this time, we can use struct to compress the number of parameters. (There are many functions with more than four parameters in MFC)
[Question] How big is the empty struct?
The memory size occupied by the struct is the sum of the memory occupied by its members (note: the memory alignment of the struct ).
# Include <cstdio> <br/> struct student <br/>{< br/>}; <br/> int main () <br/>{< br/> Student Stu; <br/> printf ("% d/N", sizeof (Stu )); // 1 <br/> return 0; <br/>}
In vs2008, the test output is 1.
[Note] the difference between struct and class
In C ++, the struct keyword and the class keyword can be used in general, but there is only one small difference. (Of course, class is used in C ++)
Struct members are public by default, while Class Members are private.
Test: Use the following code to explain: (1) the struct member is public by default. (2) functions can be defined in struct.
# Include <cstdio> <br/> typedef struct st_type <br/>{< br/> int I; <br/> st_type () <br/>{< br/> j = 1; <br/> printf ("this is constructor. /n "); <br/>}< br/> ~ St_type () <br/>{< br/> printf ("this is destructor. /n "); <br/>}< br/> void fun_in () <br/>{< br/> printf (" fun_in is in the struct. /n "); <br/>}< br/> void fun_out (); <br/> PRIVATE: <br/> Int J; <br/>} type_a; <br/> void type_a: fun_out () <br/> {<br/> printf ("fun_out is out the struct. /n "); <br/>}< br/> int main () <br/>{< br/> type_a st; <br/> St. fun_in (); <br/> St. fun_out (); <br/> printf ("% d/N", sizeof (type_a); <br/> // printf ("% d/N", St. j); // error, can not access the private member J <br/> return 0; <br/>}< br/>/* <br/> output: <br/> This is constructor. <br/> fun_in is in the struct. <br/> fun_out is out the struct. <br/> 8 <br/> This is destructor. <br/> */
(17) Union
Union maintains enough space to place one of multiple data members, instead of configuring space for each data member. All data members in Union share one space, only one data member can be stored at a time. All data members have the same starting address.
Note]
[1] A union only configures a large enough space to accommodate the maximum length of data members. In the following example, the maximum length is double type, therefore, the space size of statemachine is the size of the double data type. (Difference: the size of the struct and class is related to the byte alignment. For details, see # pragma pack (n). The default value is 4B alignment in)
For example:
# Include <cstdio> <br/> Union statemachine <br/> {<br/> char character; <br/> int number; <br/> char * STR; <br/> double exp; // 8 <br/>}; <br/> int main () <br/>{< br/> printf ("% d/N", sizeof (statemachine); // 8 <br/> return 0; <br/>}
[2] in C ++, the default property page of union members is public.
[3] union is mainly used to compress space. If some data cannot be used at the same time, union can be used.
[4] Effect of the size-end mode on Union data.
# Include <cstdio> <br/> Union <br/>{< br/> int I; <br/> char a [2]; <br/>}* P, u; <br/> int main () <br/>{< br/> P = & U; <br/> P-> A [0] = 0x39; <br/> P-> A [1] = 0x38; <br/> printf ("% x/N", p-> I ); /// 3839 (Hex .) <br/> printf ("% d/N", p-> I); // 111000 00111001 = 14393 (decimal) <br/> return 0; <br/>}
Shows the analysis.
:
High address and low address
-- Int
0 | 0 | 56 | 57
--------
-- Char
56 | 57
----
Here we need to consider the storage mode: Big-end mode and small-end mode.
Big-Endian)
: Low data bytes are stored in the high address.
Little-Endian)
: DataLow bytes
Stored inLow address
.
The space occupied by Union-type data is equal to the space occupied by the largest Member. The access to Union-type members is started at 0 from the offset of the base address of the Union, that is, the access to a consortium starts from the first address of the Union regardless of the variable. Therefore, the output result of the above program is obvious.
[5] how to use a program to determine the storage mode of the current system (large-end or small-end )?
[Problem] Write a c function. If the processor is big-Endian, 0 is returned. If the processor is little-Endian, 1 is returned.
Analysis: according to the definition of the size-end mode, assume that the int type variable I is initialized to 1.
The memory layout of the storage is as follows:
High address and low address
-- Int I = 1;
0x1 | 0x0 | 0x0 | 0x0
--------
It is stored in Small-end mode, and its memory layout is as follows:
High address and low address
-- Int I = 1;
0x0 | 0x0 | 0x0 | 0x1
--------
Variable I occupies 4 bytes, but only one byte value is 1, and the value of the other three bytes is 0. If the value of the lower address is 0, it is the big-end mode; otherwise, it is the small-end mode.
Therefore, the characteristics of Union data can be used: the starting addresses of all Members are consistent.
Method 1: Use the Union type
# Include <cstdio> <br/> int checksystem () <br/> {<br/> Union check <br/>{< br/> int I; <br/> char ch; <br/>} C; <br/> C. I = 1; <br/> return (C. ch = 1); <br/>}< br/> int main () <br/>{< br/> checksystem () = 1? Printf ("Little-Endian/N"): printf ("big-Endian/N"); <br/> return 0; <br/>}
Method 2: Use the array type
# Include <cstdio> <br/> int checksystem () <br/> {<br/> char s [] = "1000 "; <br/> return (s [0] = '1'); <br/>}< br/> int main () <br/> {<br/> checksystem () = 1? Printf ("Little-Endian/N"): printf ("big-Endian/N"); <br/> return 0; <br/>}
[Thinking]
In x86 systems (32-bit systems), what is the output value?
# Include <cstdio> <br/> int main () <br/> {<br/> int A [5] = {1, 2, 3, 4, 5 }; <br/> int * ptr1 = (int *) (& A + 1); // 0x0012ff68 <br/> int * ptr2 = (int *) (INT) A + 1); // 0x0012ff55 <br/> int * ptr3 = (int *) (a + 1); // 0x0012ff58 <br/> printf ("0x % x, 0x % x, 0x % x ", ptr1 [-1], * ptr2, * ptr3); // 0x5, 0x2000000,0x2 <br/> return 0; <br/>}< br/>
Analysis example:
High address and low address
-- | ...... -- | --------
? | 0x0 | 0x0 | 0x0 | 0x05 | ...... 0x0 | 0x0 | 0x0 | 0x02 | 0x0 | 0x0 | 0x0 | 0x01
-- | ...... -- | --------
^ (Ptr1) ^ (ptr2)
Therefore,
Ptr1 [-1] = 5 (DEC) = 0x5 (HEX)
* Ptr2 = 0x02 0x0x0 0x0 = 0x2 00 00 00 (HEX) = 33554432 (DEC)
This topic mainly examines the calculation of different offsets of pointers.
Int A [5] = {1, 2, 3, 4, 5}; // A = & A = 0x0012ff54 <br/> int * ptr1 = (int *) (& A + 1); // [1] 0x0012ff68 <br/> int * ptr2 = (int *) (INT) A + 1 ); // [2] 0x0012ff55 <br/> int * ptr3 = (int *) (a + 1); // [3] 0x0012ff58
Differences
:
A = & A [0] = 0x0012ff54
However,
A + 1 = & A [0] + 1 = 0x0012ff58 the offset at this time is: the size of an int type
& A + 1 = 0x0012ff68 the offset at this time is: the size of the entire array
[1] (& A + 1) is equal to the starting address of the array + the whole size of the array, that is, the address of the last element of the array. (Int *) (& A + 1) after forced type conversion, the pointer offset is the size of an int type.
[2] (INT) A + 1) is equal to the starting address of the array + the size of one byte.
[3] (a + 1) is equal to the starting address of the array + the size of an array element.
(18) Enum
Many beginners are confused about enumeration classes or think they are useless. In fact, Enum is a very useful data type.
[General usage]
Enum enum_type_name <br/>{< br/> enum_const_1, <br/> enum_const_2, <br/> //... <br/> enum_const_n <br/>} enum_variable_name;
Enum_variable_name is an enumeration variable of the enum_type_name type. It can only take any value in braces (enumeration constant, usually in uppercase. The enum variable can also assign values to the constant symbols. If no value is assigned, 1 is added from the constant to which the value is assigned. If no value is assigned, their values increase by 1 from 0.
For example:
# Include <cstdio> <br/> Enum color <br/> {<br/> Green = 1, <br/> Red, <br/> blue, <br/> green_red = 10, <br/> green_blue <br/>} colorval; <br/> int main () <br/> {<br/> colorval = green; <br/> If (colorval = 1) <br/> printf ("Green = 1/N "); <br/> colorval = red; <br/> If (colorval = 2) <br/> printf ("Red = 2/N "); <br/> colorval = blue; <br/> If (colorval = 3) <br/> printf ("Blue = 3/N "); <br/> colorval = green_red; <br/> If (colorval = 10) <br/> printf ("green_red = 10/N "); <br/> colorval = green_blue; <br/> If (colorval = 11) <br/> printf ("green_blue = 11/N "); <br/> printf ("% d/N", sizeof (colorval); // 4 <br/> return 0; <br/>}
[Difference between Enum and # define macro]
[1] # define macro constants are replaced in the pre-compilation phase, while enumeration constants are determined during compilation.
[2] Generally, You can debug enumeration constants in the compiler, but not macro constants.
[3] enumeration can define a large number of related constants at a time, while # define macro can only define one at a time.
[Question] What is the value of sizeof (colorval? Why? (4)
(19) typedef
Use the typedef keyword to create various -- vests
Typedef is used to take an alias for an existing data type, rather than defining a new data type. The purpose is to better express the meaning of a new name.
In actual projects, for convenience, many data types (especially custom data types such as struct) need to be applied again, at this time, typedef can help us.
Typedef struct student <br/>{< br/> // Code <br/>} stu_st, * stu_pst; <br/> struct student stu1; // same as below <br/> stu_st stu1; <br/> struct student * stu2; // same as below <br/> stu_pst * stu2;
[NOTE 1] Put typedef and const together
Const stu_pst stu3; // [1] <br/> stu_pst const stu4; // [2]
The method is that when we look at who const modifies, we can turn a blind eye to the data type name, when it does not exist. Therefore, the pointer is modified instead of the object pointed to by stu3 and stu4.
[NOTE 2] # define is a macro replacement during pre-compilation, so it is correct. The type extension is not supported for aliases obtained by typedef.
# Define int32 int <br/> unsigned int32 I = 10; // OK <br/> typedef int int32; <br/> unsigned int32 J = 10; // error <br/> typedef unsigned int int32; // OK <br/> typedef static int int32; // error <br/> # define pchar char * <br/> pchar P3, P4; // error, P3 is a pointer, however, p4 is not <br/> typedef char * pchar; <br/> pchar P1, P2; // OK, P1 and P2 are pointer
Chapter 1 keywords (summarized)