Source: Internet
1. A pipeline can achieve maximum efficiency only when it is filled with instructions, executing one instruction per clock cycle (referring only to single-cycle instructions). If a jump occurs in the program, the pipeline will be cleared, requiring several clock cycles to refill. Therefore, minimizing the use of jump instructions can enhance program execution efficiency; a solution is to utilize the “conditional execution” feature of instructions whenever possible.
2. In the LPC2200 series:
You can delay for 10 milliseconds using the following program:
for(i=0;i<200;i++){for(j=0;j<200;j++);}
3. Use the following statements to place a 16-bit variable into two 8-bit variables.
// High byte of IP datagram total length
IpHeadUint8[10]=(IpHead.e_ip.Crc&0xff00)>>8;
// Low byte of IP datagram total length
IpHeadUint8[11]=IpHead.e_ip.Crc&0x00ff;
4. When initializing all elements of an array, you do not need to specify the array length.
eg; int a[]={1,2,3,4,5};
However, if you attempt to access elements beyond a[5], the system will return random values, so this method should not be used to access elements beyond the initialized values.
5. Due to the inherent lack of support for printf in ADS, debugging can be inconvenient; you can use serial output as a substitute for printf for debugging purposes.
6. Using the OR operation can set a specific bit to 1 while leaving other bits unchanged.
eg: PINSEL0 |= 0x00000005; // Set serial port pins
This sets the 0th and 2nd bits to 1, leaving other bits unchanged.
7. Function Pointers
1> In C, the function name directly corresponds to the address of the instruction code generated for the function in memory, allowing the function name to be directly assigned to a pointer to the function.
2> Calling a function is essentially equivalent to “calling the instruction + parameter passing + return address pushed onto the stack”; the core operation is assigning the starting address of the target code generated by the function to the CPU’s PC register.
3> Since the essence of a function call is to jump to a specific address to execute code, it is possible to “call a function that does not exist in the function entity.”
4> int (*p); defines p as a pointer variable pointing to a function that returns an integer value. The parentheses around *p cannot be omitted, indicating that p is a pointer variable, which is then combined with the following, indicating that this pointer points to a function.
Difference: int *p indicates that the return value of this function is a pointer to an integer variable.
Explanation:
(1) The general definition form of a pointer variable pointing to a function is:
DataType (*PointerVariableName);
1> Here, “DataType” refers to the type of the function’s return value.
(2) A function that returns a pointer value:
TypeName *FunctionName(ParameterList)
eg: int * func(int x,int y)
func is the function name, and calling it will return a pointer to integer data. x and y are the parameters of func.
Method to distinguish:
a. Look for the first parenthesis from right to left; the parameters inside the parentheses are the function’s parameters.
b. The first identifier outside the parentheses is the function’s name, and the preceding part indicates the function’s return value.
8. Array Pointers
1> int (*p)[4]
Indicates that *p has 4 elements, each of which is an integer. Thus, p points to an array of 4 integer elements, making p a row pointer.
2> Pointer Arrays
Ø An array whose elements are all pointer type data is called a pointer array; each element in the pointer array is equivalent to a pointer variable.
Ø The definition form of a one-dimensional pointer array is:
TypeName *ArrayName[ArrayLength]
eg: int *p[4]:
Purpose: It is used to point to several strings, making string processing more convenient and flexible. It is suitable for a two-dimensional string array where each row’s character array length varies.
eg: char * name[]={“Follow me”,”BASIC”,”GreatWall”};
9. Structures
1> You can use a structure variable as an actual parameter. However, when using a structure variable as an actual parameter, it is passed by “value”, meaning the contents of the memory unit occupied by the structure variable are sequentially passed to the formal parameter. The formal parameter must also be a structure variable of the same type.
eg: print(su);// Note that su is a structure here
Note: This passing method incurs significant overhead in terms of space and time, especially if the structure is large.
2> Use a pointer to a structure variable (or array) as an actual parameter, passing the address of the structure variable (or array) to the formal parameter.
eg: print(&su);// Note that su is a structure here
10. Unions
1> A union stores several different data type variables in the same memory block. The variables in a union share the same memory.
2> The general form for defining a union type variable is:
union UnionName
{
MemberList;
} VariableList;
3> In a union, the same memory can be used to store several different types of data, but at any one time, only one member variable can be stored. The active member in the union variable is the last one that was stored.
eg: union data{int i;char c;double d;}; union data a;
The members i, c, and d of the union variable a are stored starting from the same address in memory. For example, if the following assignments are made:
a.i = 100;
a.c = ‘A’;
Then at this point, the member i of the union variable a no longer has a value, because the memory that stored that value has now been used to store the value of member c.
3> The length of a union variable depends on the maximum length of its members:
Explanation:
The length of memory occupied by a structure variable is the sum of the lengths of its members, with each member occupying its own storage space. The length of memory occupied by a union variable is the length of its longest member. Of course, the compiler often performs alignment operations when allocating storage space to improve access efficiency.
Alignment operations are based on the largest basic type. If the actual calculated length is not a multiple of the basic unit, the actual length should be a multiple of the basic unit.
(TurboC does not perform alignment, while Linux does.)
11. Handling Inconsistencies Between CPU Word Length and Memory Bit Width
For example: using a union to resolve this conflict:
union send_temp{
uint16 words;
uint8 bytes[2];
} send_buff;
eg: send_buff.bytes[0]=a;// Here a is 8 bits
send_buff.bytes[1]=b;// Here b is 8 bits;
This combines the 8-bit words into a 16-bit word for storage.
When sending, send(send_buff.words) can send a 16-bit data each time.
12. C Language Operator Precedence:
1> Compound assignment operators:
a+=3*5;
is equivalent to a=a+(3*5);
13. A common debugging strategy is to scatter some printf function calls throughout the program to determine the exact location of an error.However, the output results of these function calls are written to a buffer and are not immediately displayed on the screen. In fact, if the program fails, the buffered output may not be actually written, leading to an incorrect error location. The solution is to immediately call the fflush function after each printf used for debugging.
printf("something or other"); fflush(stdout);
14. Usage of the volatile Keyword
Volatile variables may be used in the following situations:
1> Hardware registers of devices (e.g., status registers)
2> Global variables accessed by an interrupt service routine
3> Variables shared by several tasks in multi-threaded applications.
15. Usage of the register Keyword:
When a variable is frequently read and written, accessing memory repeatedly can consume a lot of access time. To address this, C provides a type of variable called a register variable. This variable is stored in the CPU’s registers, allowing for direct read and write operations from the register, thus improving efficiency. The specifier for register variables is register. Loop control variables that are used frequently and variables used repeatedly within the loop body are good candidates for defining as register variables.
(1) Only local automatic variables and parameters can be defined as register variables. This is because register variables belong to dynamic storage, and any variable that requires static storage cannot be defined as a register variable, including: global variables between modules, global variables within a module, and local static variables;
(2) register is a “suggestive” keyword, meaning the program suggests that the variable be placed in a register, but ultimately, the variable may not become a register variable due to unmet conditions and may instead be placed in memory, without causing an error in the compiler (in C++, there is another “suggestive” keyword: inline).
16. For program code that has already been burned into FLASH or ROM, we can let the CPU read the code directly from there, but this is usually not a good practice. It is better to copy the target code from FLASH or ROM into RAM after the system starts and then execute it to improve instruction fetch speed.
The access speed of various memory types by the CPU is generally:
CPU Internal RAM > External Synchronous RAM > External Asynchronous RAM > FLASH/ROM
17. Macro Definitions
In C, macros are the only way to produce inline code. For embedded systems, macros are a great alternative to functions to meet performance requirements.
1> Macro definitions “act like” functions;
2> Macro definitions are not functions, so all “parameters” need to be enclosed in parentheses;
3> Macro definitions may produce side effects. Therefore, do not pass parameters with side effects to macro definitions.
Produced by | School Committee Publicity Department
Image | School Committee Publicity Department
© Yunnan Huasoft