Function reusability and writing specifications

Source: Internet
Author: User
Tags define function
I. reentrant Functions
1) What is reentrant?
The reentrant function can be used concurrently by more than one task without worrying about data errors. Conversely, non-reentrant functions cannot be shared by more than one task, unless they ensure mutual exclusion of functions (or use semaphores, or disable interruptions in key parts of the Code ). The reentrant function can be interrupted at any time and run later without data loss. The reentrant function either uses local variables or protects its own data when using global variables.

2) reentrant functions:
Do not hold static data for continuous calls.
No pointer to static data is returned. All data is provided by the function caller.
Use local data or make local copies of global data to protect global data.
If you must access global variables, remember to use mutex semaphores to protect global variables.
Never call any non-reentrant function.

3) Non-reentrant functions:
Static variables are used in the function, whether it is a global static variable or a local static variable.
The function returns static variables.
The function calls the non-reentrant function.
The function uses a static data structure;
The function body calls the malloc () or free () function;
Other standard I/O functions are called in the function body.
A function is a member function in singleton and uses a member variable that is not stored independently by a thread.
In general, if a function uses unprotected shared resources under the re-entry condition, it cannot be re-imported.

4) Example
Under the multi-thread condition, the function should be thread-safe. Further, the stronger condition is reentrant. The reentrant function ensures that the function State does not encounter errors under multi-threaded conditions. The following are examples of non-reentrant and reentrant functions:
// C code
Static int TMP;
Void func1 (int * X, int * Y ){
TMP = * X;
* X = * Y;
* Y = TMP;
}
Void func2 (int * X, int * Y ){
Int TMP;
TMP = * X;
* X = * Y;
* Y = TMP;
}
Func1 is not reentrant, and func2 is reentrant. Because the operating system switches to another thread when func1 is not fully executed under multi-thread conditions, the thread may call func1 again, And the status will be wrong.

Ii. Function writing specifications
1: The error return code of the called function should be carefully and comprehensively handled.

2: Define function functions and implement function design accurately (rather than approximation)

3: When writing A reentrant function, pay attention to the use of local variables (for example, when writing A reentrant function in C/C ++ language, auto is the default local variable or register variable)
Note: static local variables should not be used when you compile a reusable function in C/C ++. Otherwise, the function must be reentrant after special processing.

4: When writing A reentrant function, if global variables are used, they should be protected by means of clearance interruption, semaphores (p, V Operations), etc.
Note: If the global variables used are not protected, this function is not reentrant. That is, when multiple processes call this function, it is very likely that the related global variables are changed to an unknown state.
Example: If exam is an int type global variable, the function squre_exam returns the exam square value. The following functions are not reentrant.
Unsigned int example (INT para)
{
Unsigned int temp;
Exam = para ;//(**)
Temp = square_exam ();
Return temp;
}
If the function is called by multiple processes, the result may be unknown, because after the (**) Statement is executed, another process that uses this function may be activated. When the newly activated process executes this function, exam is assigned a different para value, so when the control returns "temp = square_exam ()", the calculated temp may not be the expected result. This function should be improved as follows.
Unsigned int example (INT para)
{
Unsigned int temp;
[Apply for a semaphore operation] // if no semaphore is applied, it indicates that another process is in
Exam = para; // assign a value to exam and calculate its square (that is, this
Temp = square_exam (); // signal), the process must wait for the signal to be released before
[Release semaphores] // resume the operation. If a signal is applied for, you can continue to execute, but its
// The process must wait until the semaphore is released by the process before enabling
// Use this signal.
Return temp;
}

5: The same project team should specify whether the caller of the function is responsible for checking the validity of interface function parameters or the interface function itself. By default, the caller is responsible for the interface function parameters.
Note: There are often two extreme phenomena about the legitimacy check of parameters of Inter-module interface functions: either the caller and the called do not check the legitimacy of the parameters, as a result, the necessary process of checking the legitimacy is omitted, which causes potential problems. Either the caller and the called are both responsible for checking the legitimacy of the parameters, however, redundant code is generated to reduce the efficiency.

6. Avoid using function parameters as working variables.
Note: using function parameters as working variables may mistakenly change the parameter content, which is dangerous. For a parameter that must be changed, it is best to replace it with a local variable, and then assign the content of the local variable to the parameter.
Example: The implementation of the following functions is not very good.
Void sum_data (unsigned int num, int * data, int * sum)
{
Unsigned int count;
* Sum = 0;

For (COUNT = 0; count <num; count ++)
{
* Sum + = data [count]; // sum is a work variable, which is not good.
}
}
If it is changed to the following, it is better.
Void sum_data (unsigned int num, int * data, int * sum)
{
Unsigned int count;
Int sum_temp;
Sum_temp = 0;

For (COUNT = 0; count <num; count ++)
{
Sum_temp + = data [count];
}

* Sum = sum_temp;
}

7: The function size should be limited to 200 rows.
Note: comments and space lines are not included.
8: A function only provides one function.

9: Write Functions for simple functions
Note: although it seems unnecessary to compile functions with only one or two rows of functions, functions can be used to clarify the functions, increase program readability, and facilitate maintenance and testing.
Example: The functions of the following statements are not obvious.
Value = (A> B )? A: B;
It is clear to change it to the following.

Int max (int A, int B)
{
Return (A> B )? A: B );
}

Value = max (A, B );

Or change it to the following.

# Define max (A, B) (a)> (B ))? (A): (B ))

Value = max (A, B );

10: Do not design all-purpose functions
Note: functions that integrate multiple functions may make it difficult to understand, test, and maintain functions.

11: The function should be predictable, that is, the same output should be generated as long as the input data is the same.
Note: Functions with internal "Memory" may be unpredictable, because their output may depend on the status of internal memory (such as a tag. Such functions are neither easy to understand nor conducive to testing and maintenance. In C/C ++, the static local variable of the function is the internal memory of the function, which may make the function unpredictable. However, when the return value of a function is pointer type, it must be the address of the static local variable as the return value. If it is an auto class, the return value is an error needle.
Example: the return value (function) of the following function is unpredictable.

Unsigned int integer_sum (unsigned int Base)
{
Unsigned int index;
Static unsigned int sum = 0; // note that it is of the static type.
// If it is changed to the auto type, the function becomes predictable.
For (Index = 1; index <= base; index ++)
{
Sum + = index;
}
Return sum;
}

12: do not compile functions that depend on the internal implementation of other functions.
Note: This is the basic requirement for function independence. Because most advanced languages are structured at present, this situation can be basically prevented by the syntax requirements and compiler functions of specific languages. However, in assembly languages, due to its flexibility, this situation may occur to functions.
Example: The following is an example of the tasm assembler in DOS. The implementation of print_msg in the process depends on the specific implementation of input_msg, Which is unstructured and difficult to maintain and modify.

... // Program code
Proc print_msg // process (function) print_msg
... // Program code
JMP label
... // Program code
Endp

Proc input_msg // process (function) input_msg
... // Program code
Label:
... // Program code
Endp

13: avoid designing multi-parameter functions. Remove unused parameters from the interface.
Note: The objective is to reduce the complexity of Inter-function interfaces.

14: Non-scheduling functions should reduce or prevent control parameters. Try to use only data Parameters
Description: This suggestion aims to prevent control coupling between functions. A scheduling function starts a function entity (a function or process) based on the input message type or control command, but does not complete a specific function. A control parameter is a parameter used to change the behavior of a function. That is, a function depends on this parameter to determine how it works. The control parameters of non-scheduled functions increase the control coupling between functions, which may increase the Coupling Degree between functions and make functions ununique.
Example: The following function is not properly constructed.
Int add_sub (int A, int B, unsigned char add_sub_flg)
{
If (add_sub_flg = integer_add)
{
Return (A + B );
}
Else
{
Return (a B );
}
}
It is better to define the following two functions.
Int add (int A, int B)
{
Return (A + B );
}

Int sub (int A, int B)
{
Return (a B );
}
15: Check the validity of all function parameter input

16: Check the validity of all non-parameter input functions, such as data files and public variables.
Note: There are two main types of function input: parameter input and global variable and data file input, that is, non-parameter input. Before using input, the function should perform necessary checks.

17: The function name should accurately describe the function Function

18: use the verb-object phrase to name the function that executes an operation. For the OOP method, only the verb can be used (the noun is the object itself)
Example: Use the following method to name a function.
Void print_record (unsigned int rec_ind );
Int input_record (void );
Unsigned char get_current_color (void );

19: Do not use meaningless or ambiguous verbs to name a function.
Note: Do not name functions with ambiguous verbs, such as process and handle, because these verbs do not specify what to do.

20: The Return Value of the function must be clear and clear, so that users cannot easily ignore errors.
Note: the meaning of each error return value of a function must be clear, clear, and accurate to prevent misuse, understanding, or ignoring error return codes.

21: Unless necessary, it is best not to compile the system's default conversion method or forced conversion method as the return value for variables of different types than the function return value.

22: Make the function easy to understand at the call point

23: When you call a function to enter parameters, minimize unnecessary default data type conversion or forced data type conversion.
Note: Data type conversion is more or less risky.

24: Avoid unnecessary statements in functions and prevent spam code in programs
Note: The spam code in the program not only occupies extra space, but also often affects the function and performance of the program. It is likely to cause unnecessary trouble for testing and maintenance of the program.

25: avoid placing Unrelated statements in a function
Description: prevents random cohesion in a function or process. Random cohesion refers to placing statements that are not correlated or have weak associations in the same function or process. Random cohesion makes maintenance, testing, and subsequent upgrades of functions or processes inconvenient. It also makes the functions of functions or processes unclear. The use of random cohesion functions is often prone to the need to improve this function in one application, and the other application does not allow this improvement, thus getting into trouble.
During programming, the same code is often used in different functions. Many developers are willing to propose the code and construct a new function. If these codes are highly correlated and complete a function, this construction is reasonable. Otherwise, this construction will generate a random cohesive function.
Example: The following function is a random cohesion.

Void init_var (void)
{
Rect. Length = 0;
Rect. width = 0;/* initialize the length and width of the rectangle */
Point. x = 10;
Point. Y = 10;/* initialize the coordinates of the "point */
}

The length and width of a rectangle have nothing to do with the coordinate of a vertex. Therefore, the preceding function is a random cohesion.
There are two functions as follows:
Void init_rect (void)
{
Rect. Length = 0;
Rect. width = 0;/* initialize the length and width of the rectangle */
}

Void init_point (void)
{
Point. x = 10;
Point. Y = 10;/* initialize the coordinates of the "point */
}

26: if multiple pieces of code repeat the same thing, there may be problems with function division.
Note: If the statements of this code segment are substantially associated with each other and complete the same function, you can consider constructing this code segment into a new function.

27: Small functions with unclear functions, especially when only one upper-level function calls it, you should consider merging it into the upper-level function without having to exist independently.
Note: too many functions are divided in the module, which may complicate the interfaces between functions. Therefore, a function that is too small, especially a function that is very low in Fan-in or with unclear functions, is not worth exists independently.

28: design high fan-in and Reasonable fan-out (less than 7) Functions
Note: fan-out refers to the number of other functions directly called (controlled) by a function, and fan-In refers to the number of upper-level functions that call it.
If the fan-out function is too large, it indicates that the function is too complex and requires too many lower-level functions to be controlled and coordinated. If the fan-out function is too small, for example, always 1, it indicates that the function may have too many calling layers, in this way, program reading and function structure analysis are unfavorable, and system resources such as stack space are under pressure when the program is running. The reasonable fan-out function (except the scheduling function) is usually 3-5. Fan-out is too large. Generally, due to the lack of intermediate layers, you can add intermediate-level functions as appropriate. The fan-out function is too small. You can further break down multiple lower-level functions or merge them into upper-level functions. Of course, when decomposing or merging functions, you cannot change the functions to be implemented or violate the independence between functions.
The larger the fan-in, the more upper-level functions that use this function, the higher the efficiency of using such functions, but cannot violate the independence between functions and simply pursue high fan-in. The functions in the public module and the underlying functions should have a high fan-in.
A good software structure is usually because top-level functions have a high fan-out ratio, while middle-level functions have a small fan-out ratio, while underlying functions have fan-in to public modules.

29: reduce recursive calls between functions or functions
Note: recursive calls, especially between functions (for example, a-> B-> C-> A), affect program comprehensibility; recursive calls generally occupy a large amount of system resources (such as stack space). recursive calls have a certain impact on program testing. Therefore, unless it is convenient to implement some algorithms or functions, unnecessary recursive calls should be reduced.

30: carefully analyze the functional and performance requirements of the module and further segment the module. At the same time, if necessary, draw a data flow diagram and divide and organize the functions of the module accordingly.
Note: The Division and organization of functions is a key step in the module implementation process. How to divide a reasonable function structure is related to the final efficiency, maintainability, and testability of the module. It is one of the common methods to map the function structure based on the module function diagram or/and data flow diagram.

31: Improve the function structure in the module, reduce the Coupling Degree between functions, and improve the independence of functions and code readability, efficiency, and maintainability.
When optimizing the function structure, follow the following principles:
(1) The implementation of module functions cannot be affected.
(2) carefully examine and improve module or function error handling and module performance requirements.
(3) Improve the software structure by decomposing or combining functions.
(4) Examine the scale of the function. If it is too large, it should be decomposed.
(5) reduce the complexity of Inter-function interfaces.
(6) function calls at different levels should have reasonable fan-in and fan-out.
(7) functions should be predictable.
(8) Improve Function cohesion. (Single function has the highest cohesion)
Note: The function structure after preliminary division should be improved and optimized to make it more reasonable.

32: programming in the multi-task operating system environment, pay attention to the construction of function re-entry
Description: reusability means that a function can be called by Multiple Task processes. In a multitasking operating system, it is very important to check whether a function is reentrant, because this is a necessary condition for multiple processes to share this function. In addition, whether the compiler provides the reentrant function library depends on the operating system it serves. Only when the operating system is multi-task can the compiler provide the reentrant function library. For example, in DOS, BC and MSC do not have backup function libraries, because DOS is a single-user single-task operating system.

33: Avoid using bool Parameters
Note: There are two reasons. One is that the bool parameter value is meaningless, and the meaning of true/false is very vague. It is difficult to know what the parameter actually means during calling; the second is that the bool parameter value is not conducive to expansion. Null is also a meaningless word.

34: for a function that provides a return value, it is best to use its return value when referencing it.

35: when a process (function) has many references to long variables (usually structure members), it can be replaced by a macro of the same meaning.
Note: This increases programming efficiency and program readability.
Example: thereceivebuffer [firstsocket]. bydataptr,
The following macro definition can be used instead:
# Define psockdata thereceivebuffer [firstscoket]. bydataptr

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.