I have read the famous "the C programming language". As I have heard, I have a thorough explanation of the basics and a typical case. I do not know much about the C language.
Summary of the reading results (some of the original book's unclear knowledge points are added after searching on the Internet, the reference source is forgotten, and the original author can contact to add)
1. Statement
1.1 variable Declaration
In C, all variables must be described first and then used. The description is usually placed before the executable statement at the beginning of the function.
1.2 external variables
Declare the external variables to be accessed in each function. The type of the external variable used for declaration can be explicitly described with extern during declaration, or implicitly explained through context. If the definition of an external variable appears in the source file before its function is used, the extern declaration can be omitted.
If the program contains several source files and a variable is defined in file1 and used in file2 and file3, the extern declaration is required in file2 and file3 files to connect to the variable.
The variable extern declaration and function declaration are placed in the header file.
1.3 declared Style
Old declared style: print (); (Save the return value int to simplify encoding)
New declared style: void print (void)
Advantages of the new style: the compiler helps to better check function calls
For example:
Print (5.5 );
In the old style, this call to the compiler does not report an error (because the parameter list has no content, it means that the parameter list is not checked)
In the new style, the compiler reports an error
1.4 Importance of declaration (inverse example of compiler check)
In the same source file, the function declaration must be consistent with its definition; otherwise, the compilation is incorrect. However, if the function is compiled independently, this mismatch will not be detected. Because the C language automatically performs implicit Declaration on functions without function declaration, the compiler will not only detect the return value, but also the parameter list.
Main. c
printf(“%f”,getNum( }
Get_num.c
get_num( }
There will be no compilation errors. Remember to use the function declaration.
By default, external variables and functions have the following properties: All references to external variables and functions by name (even if such references come from independently compiled functions) are referenced with the same object.
2. Memory Layout
Length of 2.1 int bytes
Length of int in C Language
1. long int type should be at least as long as int type, while int type should be at least as long as short int type;
2. C/C ++ specifies that the length of an int is the same as that of a machine.
3. The operating system font length may not be consistent with the machine font Length
4. the compiler defines the int Length Based on the operating system length.
From the above four points, we can see that in some embedded computer systems without an operating system, the word length of the int is the same as that of the processor. When an operating system is available, the word length of the operating system is not necessarily the same as that of the processor, in this case, the compiler defines the int Length Based on the operating system length. For example, if you run the DOS 16-bit system on a 64-bit machine, the int values in all C/C ++ compilers for dos are 16-bit; if the win32 system is run on a 64-bit machine, the int values in all C/C ++ compilers for win32 are 32-bit.
Cause:
The operating system determines the hardware management mode at the software level. If the management mode for 64-bit machines is still 16-bit (for example, the memory access address is only 216 ), then the 64-bit machine actually only plays a 16-bit role.
Different platforms have their corresponding instruction sets and compilers. This is the reason why C language is portable at the source code level. If different compilers are used on different platforms, the program running results must be the same even if the binary machine code obtained is different.
Therefore, when defining data structures (especially embedded), excellent programmers do not define the following (32-bit ):
typedef unsigned unsigned }TypeExample;
They define this as follows:
unsigned short UINT16 unsigned int UINT32 typedef }TypeExample;
According to the IEEE754 standard, the memory layout of float and double is as follows:
Symbol bit S (1 bit) + index (8 bits) + ending number (23 bits)
Float Length 32 characters
Calculation method:
It is an exponential shift code, and the offset is 127.
The tail number saves the first digit of the highest digit and is only used as the binary representation after the decimal point.
(-1) ^ S (1 + ending number) * 2 ^ (exponential-offset number)
Example: 3.0 = 11 = (-1) ^ 0 * (1.1) * 2 ^ (128-127)
Therefore, the symbol bit is 0, the index is 1298, And the ending number is: 1 + 22 0
So: the float of 3.0 is: 0 10000000 10000000000000000000000 = 0x40400000
Verification:
#include <stdio.h> t.b = printf( }
Output result: 3.000000
Therefore, the index is 127 ~ 128, range: 2 ^-127 ~ 2 ^ 128
Ending number: hidden 1 remains unchanged without affecting precision. 2 ^ 23 = 8388608, a total of seven digits, which means that there can be a maximum of seven valid digits, but it is absolutely guaranteed to be 6 digits, that is, the float precision is 6 ~ 7-digit valid number.
Similarly, for the memory layout:
Symbol bit S (1 bit) + index (11 bits) + ending number (52 bits)
For the double type, the analysis is the same.
Range:-2 ^ 1023 ~ + 2 ^ 1024
Valid number: 2 ^ 52 = 4503599627370496, a total of 16 digits. Similarly, the precision of double is 15 ~ 16 bits.
3. Type
3.1 portability of char Variables
When defining a variable, only the keyword char is used. By default, it is defined as signed or unsigned according to the compiler, which leads to different char values on different machines.
If the characters are explicitly declared as signed or unsigned, the portability of the platform can be improved. However, if the machine processes signed and unsigned differently, the efficiency may be impaired. The parameter declaration of library functions with different processing characters is char, which causes compatibility problems.
Conclusion: The best method to ensure portability is to define it as a char type and explicitly use it when performing arithmetic operations, only the intersection characters of signed char and unsigned char are used.
3.2The operation component is upgraded before the operation.
If an arithmetic operator has a floating point component and an integer component, the qualified integer component will be converted to the floating point type before the operation starts.
The expression first converts the type and then computes z = (n> 0 )? F: n
Whether n is positive or not, the z type is float.
3.3 floating point Constants
Floating Point constant Ctrip has a decimal point. Example: 3.0
3.4 use the unsigned char type to accept ASCII code
unsigned ( (c=getchar()) != }
The EOF macro value is-1, while unsigned char cannot accept-1, so it will never reach the end of the file
3.5 constant representation
<Limits. h> and <float. h> contain all these types of symbolic constants and other properties of machines and compilers.
Long constants must end with letters L or l.
Unsigned number ending with u or U
The suffix ul or UL is used to indicate the unsigned long constant.
Floating Point constant representation: 123.4 or 1e-2, no suffix is double, suffix f or F is float, suffix l or L is long double
3.6 hexadecimal Representation
Decimal 31 octal 037 hexadecimal 0x1F binary 0b00011111
3.7-bit modulo
Use bitwise mode to specify the ASCII code corresponding to the character
Vertical ASCII code Tab
11' \ V'
= '\ Xb' ('\ xhh' hh is a hexadecimal number of at most 1)
= '\ 013' (' \ ooo' is one to three octal values)
3.8 String Representation
The C language has no limit on the length of the string, but the program must scan the complete string ('\ 0' Terminator) to determine the length of the string.
Strlen returns the string length, excluding the Terminator.
3.9 Enumeration type
Enumerated constant
1. enum boolean {NO, YES };
Enumeration value increases from 0 NO = 0 YES = 1
2. enum month {JAN = 1, FEB, MAR, APR };
JAN = 1 FEB = 2 MAR = 3 APR = 4
3. enum escapes {BELL = '\ A', BACKSPACE =' \ B ', TAB =' \ t', NEWLINE = '\ n '};
Show specified enumerated values
Try to replace # define with const, enum, and inline. You can replace the Preprocessor with the compiler)
The macro replaces the text in the code segment during preprocessing. When the program is running, the macro does not exist. Enumeration works after the program runs. Enumeration constants are stored in the static storage area of the data segment, and macros occupy the space of the code segment. enumeration not only occupies space, but also consumes CPU resources.
Enumeration type values can be automatically generated, which is an advantage over # define
3.10 automatic Variables
Only variables defined within the function. It only allows you to use it within the function that defines it, and is not available anywhere outside the function. The system automatically allocates and recycles the storage space of automatic variables. its lifecycle is the function returned from which they are defined to which they are defined. This process is implemented through a stack mechanism. Allocating memory for automatic variables is the pressure stack, and returning is the rollback stack.
3.11 static variables
Unlike automatic variables that use the stack mechanism to use memory, they allocate fixed memory in the static storage area. Continuity is the entire program running cycle. The scope is the internal function that defines it.
Use extern to access global variables defined in other files. If static is used to declare variables outside the function, other files cannot use this variable. Const int a declaration can only be used in files defining a function.
3.12 register variables
To improve access efficiency, the compiler determines whether registers are used. The address cannot be accessed.
register ra asm(“ebx”);
3.13 loss-prone Variables
Enforce access operations to prevent the compiler from being optimized and tell the compiler to take values from memory rather than from registers or caches.
3.14 non-automatic Variables
Non-automatic variables include: global variables + static variables
Non-automatic variables are initialized only once. They are performed before the program starts and the initialization operator is a constant expression. The default value is 0.
The function where the automatic variable is located is initialized. Its initialization character can be any expression and the uninitialized value is undefined.
4. type conversion
4.1 int to char Conversion
Essentially, it is only the conversion of the ing relationship of an ASCII code table.
The C language has built-in ing relationships. The char type is used to manage characters. In fact, the ASCII code value is managed, and the ing to characters is completed at the final output.
When an int value is assigned to a char, memory truncation is essentially performed.
Example:
a = c = pritnf(“%c”,c);
The result is.
a = c = printf(“%c”,c);
The result is the same as.
ASCII code table 0 ~ 255 (0 ~ 127 standard ASCII code 128 ~ 255 extended ASCII code)
4.2 char to int Conversion
The C language does not specify whether the char type is signed or unsigned. Therefore, when you convert the char type value to the int type value, it varies depending on the machine.
If the leftmost part of some machines is 1, it is converted to a negative integer, while the others are upgraded. Add 0 to the leftmost part.
Code:
a = b = printf(“% }
Precise definition of forced type conversion:
The expression is first assigned to a variable of the specified type of the type name (the corresponding memory layout is automatically constructed), and then used in the position of the entire structure.
Parameters are declared through the function prototype. Generally, when a function is called, the system automatically enforces type conversion for the parameters. However, for printf, format controllers such as % f only determine the interpretation of corresponding parameters, and do not perform forced type conversion.
Before calculation, the "low" type is first raised to the "high" type for the calculation component.
4.4 automatic float Conversion
Note: The float type computation component in the expression is not automatically converted to the double type, which is different from the original definition. Generally, mathematical functions require dual precision. The main reason for using the float type is to save storage space when using a large array, and sometimes for machine execution time (double precision calculation is particularly time-consuming)
4.5 automatic conversion of the unsigned type
The conversion rules are more complex when the computation component contains the unsigned type. The main problem is that the comparison between signed and unsigned values depends on the machine because they depend on the size of each integer type.
If int is 16 bits, long is 32 bits
-1L <1U because the unsigned int will be converted to the signed long type.
-1L> 1UL, because-1L will be converted to the unsigned long type
5. Operation
Order of assignment operations: from right to left
5.2-bit operation
For example, use the bitcount function to count the number of BITs whose value is 1.
Method 1: Match and shift each bit until x is 0
Bitcount (unsigned (B =; x! =; X >>== (x & B ++}
Method 2: remove the rightmost 1 of the variable until the variable size is 0.
Bitcount (unsigned (B =; x! =; B ++ x & = (x -}
5.3 expression type conversion before Calculation
Such as computing:
Z = (n> )? F: n;
Whether n is positive or not, the z type is float.
5.4 order of variable values in function calls
In function calls, the order in which each variable is evaluated is not specified.
Printf ("% d \ n", ++ n, power (, n ));
Errors. Different compilation programs decide whether to execute ++ operations on n before power (2, n ).
Therefore, it is rewritten:
+ % D \ n ", n, power (, n ));
5.5 plus one, minus the side effects of one operation
A [I] = I ++;
If the array subscript is an old value or a new value, the compiler may have different interpretations on it and treat it as different interpretations to produce different results.
5.6 use of ternary Operators
The use of ternary operators can effectively save the code length, such:
(I =; I <; I ++ % d % s ", I, (I! = )? "": "\ N ";
6. Statements
6.1 if, while, for condition tests really mean "not 0"
6.2 switch statement
In a switch statement, the role of the case scenario is like a label. After the code in a case is executed, it is executed in the next case unless it is displayed to control the transfer.
6.3 The comma operator (,) can be used in a for loop. Multiple Expressions are supported.
6.4 variables and functions can be declared together.
Sum, atof ([]);
7. Others
7.1 printf (standard library function)
% D decimal % o octal % x hexadecimal % f = % lf
Add h short integer and l long integer
The width and precision in printf can be controlled by the * number.
For example:
Printf ("%. * s", max, s );
% Followed by-Symbol Expression left alignment,
For example:
A = %-4d ", );
When defining a function with a variable length parameter table such as printf, the parameter table must have at least one parameter
Minprintf (* fmt ,...);
7.2 differences between definitions and declarations
Definition: location where a storage unit is created or allocated to a variable
Declaration: Specifies the location of the variable nature and does not allocate storage units
7.3 variable definition is not only available at the beginning of the Function
7.4 array Initialization
Array initialization. The uninitialized part is set to 0 automatically.
Character array Initialization
Pattern [] = pattern [] = "'O', 'U', 'l', 'D ','\'";
7.5 macro definition
7.5.1 add and subtract one in macro definition
Max (A, B) = (A)> (B )? (A): (B ))
This macro adds two times to the input I ++ scenario.
7.5.2 string in macro definition
Parameter names are prefixed with "#", so they are extended by parameters replaced by actual parameters into strings with quotation marks.
Dprint (expr) printf (# expr "= % g \ n", expr );
Dprint (x // y "= % g \ n", x/y );
Output result: x/y =?
7.5.3 ## provides a method for macro expansion to connect actual parameters
Paste (front, back) front # back );
7.5.4 # The if statement contains a constant integer expression (which cannot contain sizeof, force type conversion operator, or enumeration constant ), in the # if statement, you can use a special expression defined (name ).
! Defined (EDR) HDR ....
Two special expressions
# Ifdef = defined (***) =! Defined (***)
7.6 The address fetch operator can only be applied to memory objects and cannot be used to operate expressions, constants, or register variables.
7.7 const qualifier
1. Use const to modify general Variables
The variable modified by the const must be initialized during the Declaration. Once a variable is modified by the const, it is wrong to assign values to this variable except initialization in the program.
2. Use const with pointer
Pointer constant, that is, the value of the pointer itself cannot be changed.
Constant pointer, that is, the value of the variable pointed to by the pointer cannot be changed.
Const int * p and int const * p1; const describes the content pointed to by the pointer
Int * const p2 = & B; const describes the pointer itself
The variable modified by const needs to be initialized.
3. As function parameters
4. saves space and avoids unnecessary memory allocation.
From the Assembly perspective, the const definition constant only gives the corresponding memory address, rather than giving the immediate number like # define. Therefore, the const-defined constants have only one copy during the program running, while the # define-defined constants have several copies in the memory.
5. the compiler usually saves them in the symbol table instead of allocating storage space for common const constants. This makes it a constant during compilation. Without the storage and read memory operations, the efficiency is also very high.
6. Prevent Users From modifying function return values
7. const member variable initialization in the struct
A s = {,};
Same as struct Initialization
8. const is a read-only variable.
N = a [n];
Error. Const is a read-only variable, but not a constant.
9. Contents limited by the const variable & const
Typedef * [] = * p1 = pStr p2 = ++; p2 ++;
Analysis:
1) The basic form used by const: const char m limit m unchanged
2) Replace m, const char * pm in Formula 1; Limit * pm is unchangeable. Of course, pm is variable, so p1 ++ is correct.
3) Replace 1 char const newType m; Limit m is immutable. pStr in the problem is a new type, so p2 in the problem is immutable. P2 ++ is incorrect.
10. string constants and character Arrays
Char * c = "Hello World"; character constant
Char c [] = "Hello World"; character array
String constants exist in the static storage area (read-only, in the rodata segment)
Place character arrays in the Dynamic Storage Area
Therefore, the string constant cannot be modified. c [1] = 'A'