From: codingwu-Blog Park
Author: Archimedes
Source: http://www.cnblogs.com/archimedes/
This article is translated from: http://www.codeproject.com/Articles/6154/Writing-Efficient-C-and-C-Code-Optimization
It refers to the article: http://www.cppblog.com/xlander/archive/2006/07/21/10289.html
But the code format in the article is not typeset, inconvenient to view, and there are some translation errors and other errors, this article in addition to reference to the original text and translation, but also added some of their own understanding and code, although it is a 2006-year article, but some of these skills are quite worth learning, and special reorganization to share with you.
While there are many effective guidelines for optimizing C code, the speed with which you get to know the compiler and the work you're working with is still not going to take place, and speeding up the program also increases the amount of code. These added code can also affect the complexity and readability of a program, this is not acceptable, for example, if you are programming on a small device, such as a mobile device, a PDA ..., these have strict memory limits, so the motto in optimization is: Write code in memory and speed should be optimized.
Integer number/integers
When we know that the number of uses can not be negative, you should use the unsigned int instead of int, some processors handle integer arithmetic when the unsigned int faster than int, so, in a compact loop inside the definition of an integer variable, it is best to write code:
Register unsigned int variable_name;
However, we cannot guarantee that the compiler will notice the Register keyword, and it is possible that for some processor, there is no unsigned. These two keywords are not available for use in all compilers. Remember, the integer operation is much faster than the floating-point number, because the processor can directly perform integer operations, floating-point operations need to rely on the external floating-point number processor or floating-point math library. We need to be more precise when dealing with decimals (for example, when we're doing a simple statistical program), limit the results to 100, and turn it into floating-point numbers as late as possible.
Division and Remainder/division and remainder
In a standard processor, depending on the numerator and denominator, a 32-bit division requires 20-140 clock cycles to perform, equal to a fixed time plus the time each bit is removed.
Time (numerator/denominator) = C0 + c1* log2 (numerator/denominator)
= C0 + C1 * (log2 (numerator)-log2 (denominator)).
Now the ARM processor needs to consume 20+4.3n clock cycles, which is a very time-consuming operation to avoid as much as possible. In some cases, a division expression can be overridden by a multiplication expression. For example, (A/b) >c can be written as a> (C*B), provided that we already know that B is non-negative and that b*c does not exceed the range of integer numbers. If we can determine that one of the operands is unsigned, then it would be better to use unsigned division because it is much faster than signed division.
Merging Division operations and Division operations/combining and remainder
In some cases, both the division and the remainder operations are needed, in which case the compiler merges the division and the rest operations because the division operation always returns both the quotient and the residue. If two operations are to be used, we can write them together.
int func_div_and_mod (int a, int b) {return
(A/b) + (a%);
}
Divisor is the division of the power of 2 and the remainder/division and remainder by powers of two
If the divisor in the division is a power of 2, we can further optimize the division operation, and the compiler uses the shift operation for this division operation. So, we want to adjust the power of 2 (say 64 instead of 66) as much as possible. If it is unsigned, it is much faster than a signed division.
typedef unsigned int uint;
UINT DIV32U (uint a) {
return A/32;
}
int div32s (int a) {
return A/32;
}
Both divisions avoid calling the division function, and in addition, unsigned division uses fewer instructions than a signed division. A signed division takes more time, because the division is the end result tends to zero, while the shift tends to negative infinity.
Substitution of modulo operation/an alternative for modulo arithmetic
We typically use the remainder operation for modulo, but sometimes it is possible to rewrite using an if statement. Consider the following two examples:
UINT MODULO_FUNC1 (UINT count)
{
Return (++count% 60);
}
UINT MODULO_FUNC2 (UINT count)
{
if (++count >= 60)
Count = 0;
return (count);
}
The second example is preferable to the first, because the code generated by it is faster, note: This is only when the count range is between 0–59.
But we can use the following code (the author added) to implement the equivalent function:
UINT MODULO_FUNC3 (UINT count)
{
if (++count >= 60)
Count%= 60;
return (count);
}
Use array index/using array indices
Suppose you want to set another variable to a specific character based on the value of a variable, and you might do this:
Switch (queue) {
Case 0:letter = ' W ';
Break
Case 1:letter = ' S ';
Break
Case 2:letter = ' U ';
Break
}
or so:
if (queue = 0)
letter = ' W ';
else if (queue = 1)
letter = ' S ';
Else
letter = ' U ';
A simple and quick way is simply to make the value of a variable a string index, for example:
static char *classes = "WSU";
letter = Classes[queue];
Globals/Global Variables
Global variables are not assigned to registers, and modifying global variables is done indirectly through pointers or by calling functions. So the compiler does not store global variables in registers, which can create additional, unnecessary burdens and storage space. So in the more critical loops, we don't use global variables.
If a function uses global variables frequently, we can use local variables as copies of global variables so that registers can be used. The condition is that any child functions called by this function do not use these global variables.