Disclaimer: This article is published in the 5th issue of programmer this year, slightly deleted, non-via the magazine and written permission of the magazine, please do not discount some or all content without authorization.
Goodworship, the enemy does not know its attack. - Sun Tzu War Fabric 1 General Theory NO PROGRAM IS BUG-Free, this is a proposition that cannot be proved but universally recognized in software engineering. If the software test is regarded as the "attack" that is launched to the potential bug of the five flowers, the production of high-quality and reliable code can be seen in the software coding process, it can be seen to resist the potential design defects and running errors. "Work. It can be said that an error and an exception handling mechanism (Error / Exception Handling Mechanism) is a critical factor that determines software quality and reliability, and is one of the focus of interest in software engineering. When a project starts, it is often considered what kind of wrong / anti-wrong design and an abnormal processing mechanism.
The description of the grandchildren's highest realm of defense is: "I don't want to fight, although the land is defeated, the enemy must be with my warrior, but also for software coding, it is limited time Inside, delivery stable and reliable procedures, avoid errors due to design and loss, and for various runtime possible abnormalities can correctly process, not caused by "catastrophic consequences", etc. . 2 Distinguish between mistakes and abnormal grandson: "Water is cooked in the ground, the soldiers win", and for the preparation of reliable and stable code, we must first clear what we face "enemies", thus for different The enemy takes different strategies. Here we must emphasize that it is necessary to clarify the "error" and "exception" in the software, it is worth noting that "exception" is a broad concept, and it is not equivalent to modern software programming. The Try / Throw / Catch exception handling mechanism in the language, the latter is just a solution to the former, which has been discussed in detail later.
Let's first take a look at an error and exception:
"Error ... INDICATES SERIOUS PROBLEMS THAT TO CATCH. MOST Such Errors Are Abnormal Conditions." (Error "is a rational program should not try to capture serious problems, most such errors are not normal) "EXCEPTION ... INDICATES CONDition to catch." ("Exception" is a reasonable manager of the reason that the initial programming is the most probably confirmed, which is to confuse the difference between the two. From the above definitions we can see that the commonality of the two is the unspected conditions that we don't expect to occur during program development, and the differences between the two are also very obvious:
First, from the Timing Domain: Error is that the program is "Run-Time" "should not be captured", that is, it means that it should be designed before the wrong prevention should be operated. (DESIGN-TIME); an abnormality is a Run-time must be and should be captured and processed;
Second, from the Handling Mechanism (Handling Mechanism): For errors, because we cannot capture it during runtime, more is to take monitoring, discover, thus correct (wrong), or to ensure potential Errors do not bring catastrophic consequences to prevent (anti-wrong) in programming; for exceptions, we are more concerned about capturing, thereby handling it. The difference between the differences and its processing mechanisms will be described below, and a complete example is given in the actual project using a specific example. 3 The wrong design and the wrong mistake design are generally meaningful, there are two types of errors, syntax error, logic error, this article, we mainly discuss the latter (strictly said, just the latter A subset of the code, that is, the code is illegal after the code is compiled after designing logic defects.
The following is given to a simple example (such as non-especially specified, the examples of this article are written in C ):
INT Z = X / Y; this statement does not seem to have any problems, and the fact is true? If the value of the division y is 0 when the statement is executed, the Divided By Zero will generate, and for the division, we never allowed to be 0, if it really happens, meaning The front-ended error assignment is incorrect here.
Below is an improved approach, using the assertion mechanism to monitor, we call "Amogenic Design":
Assert (y! = 0); int z = x / y;
Assert is an assertion macro in the C standard library assert.h, which causes an assertion error in the program's debug version when the Boolean expression is taken to Boolean. ) Thus report to programmer (usually also terminated), this is the assertion mechanism that is often used in modern programming (commissioning) technology. By setting some specific checkpoints in some code to check if some specific conditions are met, come Help the judgment program is correct.
A deficiency of assertions is that it is only in the debug version of the program, which does not work for the release version, that is, if the division operation is performed in the release version of the program, Y is unfortunately taken to zero Value, still possible consequences. Please see another possible design is:
INT Z; if (y! = 0) {z = x / y;} else {// deal with this situation here}
This kind of writing is called "anti-wrong design", and it has the advantage that Y is still incorrectly taken from 0, and it is not possible to crash, but the defect is, If Y does not take 0, then this anti-wrong design is in fact concealing errors, it is worth mentioning that Steve MAGUIRE in Writing Clean code: "The anti-wrong programming is often known as Good coding style, but it hides the error. To remember, the mistake we are talking about should never happen again. "But the author said," Although the anti-mistable programming will conceal the error, but it does value The worst result that can be caused by a program is to perform crash, and the user may spend a few hours of the data to be lost. In the non-ideal world, the program is indeed awkward, so in order to prevent user data from being lost Any measures are worth it. "It is worth thinking twice. Here is another example: file * fp = fopen ("c: //test.txt", "r"); int CH = Getc (fp);
Perhaps careful readers have already classically launched the unique designs, if the first sentence is open, the input of the second sentence will clearly lead to unknown results, and should be corrected to:
File * fp = fopen ("c: //test.txt", "r"); if (fp! = Null) {INT CH = fgetc (fp);} else {// deal with this situation here} here We chose the "anti-wrong design" said by Steve Maguire rather than a simple adoption of the assertion mechanism in the debug version, because the file does not open this situation in the real situation. But please pay special attention to the reader not to confuse the error and abnormality treatment, where fp == NULL is indeed I / O "exception", but we discussed that the empty pointer is used as the fgetc () function Function input parameters are constituted a "error" instead of "exception". For the case where the found fopen returns NULL (in fact, "the" Return Value "exception handling mechanism is used herein, and the programmer is indeed (many times, it must be required) to process it as" exception ". But please note that the concepts are conceptually distinct. About anti-wrong design, the following is another typical example (adapted from Writing Clean Code):
Char * p; char * pend; / * Somehow make P Point To a Memory Block, Pend Indicates Boundary Of it * / while (p Try the left and right code, it seems that the function is not different. Imagine, if you have access to the loop (such as the border memory reading, or even "Cosmic Ray", STEVE MAGUIRE, so that the right code will cause the cross-section of memory block to read and write, The left code will be slightly loop, protect the memory block, so the left is "anti-wrong design". But it does have a possible concealed error, so you can consider adding an assertion Assert (P The first is "Amor's Design" and uses the assertion mechanism. If you do anything hidden assumed, you can confirm the assumptions or not, so that you find it when debugging and testing, but there is no effect on the release. The second is "anti-wrong design", by joining the appropriate conditions, making the destructive consequences even if it is not established in the distribution version, but the anti-wrong design may increase the difficulty of finding errors, And since the code to increase the conditional judgment portion may affect the performance of the release version. Basic choice ideas is that if you logically do some hypothesis (that is, some states are inevitable or inevitable), it is usually necessary to use assertions to monitor in debug versions; I hope that even if it is also prevented even in the release version, the wrong mist design should be selected. It should be pointed out that these two error handling methods do not contradict, in fact, they are usually used in the project, making it incapaci errors while preventing errors, and the drawback is increasing. 4 abnormal capture and handling so-called exception, simply, the "very" event that cannot be in the designed time when runtime, which is usually related to the specific operational environment and resource allocation. The best programmers cannot know when writing a new statement applied for a memory, this statement will not apply for the required memory space when it is really executed on a machine, and write a next open file. When the FopEN statement is not possible, it is not expected whether this file is inevitable on each machine; moreover users often use software as programmers. Therefore, for an abnormality, we cannot monitor or prevent like a mistake, which can only be applied properly, and its fundamental purpose is not to avoid abnormal occurrence, because abnormal is essentially unavoidable, but When it occurs, it will not cause disasters. Many articles have been discussed in detail to discuss abnormal capture and processing mechanisms, and common abnormal treatment methods have the following: I Utilize the function return value When running anomalies during a function execution, the most common way is to return a predefined error value, and can be subdivided into two categories. One type is to return a Boolean value, with TRUE / FALSE indicates whether the function calls success; the other class is a series of error values in advance, raising the return value of HRESULT commonly used in Windows as an example. Flag Description Numeric Value S_OK Operation Successful 0x00000000 E_OUTOFMEMORY FAILED TO Allocate Necessary Memory 0x8007000E E_POINTER INVALID POINTER 0X80004003 Different return values represent different error types. After each function call that may generate an exception, check the return value to capture an exception, and select a different processing branch based on the return value, which constitutes a complete capture-processing mechanism. II Setting Global Sign Mechanism The basic idea is an error flag that sets the global (relatively) when an error occurs. Thus, you can check if an abnormal situation occurs, such as Win32S DWORD GetLastError (Void); each call is returned to an error value of the thread. Errno (Runtime Library) supported by Errno is also a solution (below, the author is from MSDN, the author is robert schmidt): # include INT main (void) {double x, y, z; / * ... Somehow set 'x' and 'y' ... * / errno = 0; Result = POW (x, y); if (errno == Edom) Printf ("Domain Error On X / Y PAIR / N); Else IF (" Range Error On Result / N "); Else Printf (" x to the y =% D / N ", (int) result; return 0;} This complete example reflects that the C language uses global flag errno for abnormal capture and processing, that is, check the global flag after each time you may bring an abnormal operation. This method can expand to utilize a global error stack so that exceptions greater than once. Two methods of I and II are often combined, and many existing systems use such a composite mechanism, such as C Runtime Library, Windows API, etc. The III Try / Throw / Catch mechanism finally mentioned this perhaps the most famous abnormal processing mechanism, which is known as the high-level language such as modern C / Java / C # introduced this mechanism, so many people mentioned The exception thought it, its basic idea is to separate the program workflow and the error handling process "structured", and the mechanism, due to the more complex, and many books and articles have detailed discussion, this is no longer Expand. Many literatures have referred to a fact that several exception handling mechanisms have their own advantages and disadvantages, and it is difficult to find an absolutely excellent universal abnormal treatment method. We also agree with this view, and thus choose an abnormal mechanism to become a more than an abnormal mechanism itself. Important questions, the following few basic considerations in the project: 1) Never avoid an abnormal situation, and go to "bold" assume that your program will always apply to the memory space, and the document you want to open will always exist. 2) Try to select a consistent exception handling mode in a software project, and it should be determined and implemented in the beginning, there is a view that a software project should first begin in "assert.h" and "error.h". Two headers, although there are some exaggeration, but not reason; 3) Selecting an abnormal handling mechanism should fully consider the programming language and development environment for use, such as for the development environment of Java, using the third mechanism (abnormality) is very Naturally, and in some cases we need to customize the development environment of the project, for example, for efficient considerations, sometimes the C TROW / CATCH exception mechanism is disabled, and in the embedded environment, C The abnormal mechanism itself is often unavailable. 5 instance errors and exceptions are inherently a non-normal program state, in the program design practice, the two is in fact difficult to separate, the following is a comprehensive example, we want to design a function, with the specified characters and Fill the number of fills a memory address: #include INT Fill_buf (CHAR CH) {Assert (start! = null); if (count <= 0) RETURN E_INVALID_ARG; for (int i = 0; i Void Main (int Argc, char * argv []) {int count = -1; if (argc == 2) {count = ATOI (Argv [1]);} else {printf ("Wrong parameter number");} Char * buf = null; buf = new char [20]; assert (buf! = null); INT ERR = Fill_BUF (BUF, Count, "S"); if (Err! = E_OK) {Printf ("Fail to Fill A Buffer");} else {printf ("Fill A Buffer SuccessFully with% D Characters", count }} First look at the Fill_buf () function, first check if the input parameter is illegal, for the case of incoming empty pointers, we think this is a case in which the procedures in formal delivery should never exist, so we chose the assertion macro test, For the count value, we take the negative value as an abnormality process, and use the return value to return to the call to capture, and this is also a defender design (for the back memory write operation), here we have seen it again. Active error design and exception handling "symbiosis" example. It should be noted that if the return value of the function is ignored by the caller, it may hide an error (maybe this is what we have habit). In the main () function, we check the ARGC's check is to prevent the anti-wrong designs of the AGRV illegal reference, and select different screen output by checking the FillBuf (), selecting different screen outputs, and breaks up the input situation of Count <0 For an abnormality, since count is dynamically entered by the user during runtime. At the same time, it can be found that if an error in the distribution of memory failed in the release, it will lead to illegal operations of memory (because assertions are failed to fail), this is to consider existing virtual memory operation system environments, allocation The possibility of failure of memory is minimal, so it does not require anti-wrong design. 6 The error / abnormal handling of the conclusion procedure has already caused continuous attention from the technical community. This article is intended to talk about their difference, contact and processing methods from a macroscopic perspective, so that the reader has a integrity grasp and framework. Awareness. For more specific micro-techniques details, readers can refer to other literature, such as the Writing Clean Code of Steve Maguire, there are many in-depth discussions, and the literature on abnormal processing is even more numerous. .