Original: Common C programming error

xiaoxiao2021-03-06  104

Common programming error

We summarize some simple and common programming errors, which are specially lever for examples of potential hazards for reference, and hope to help you.

First, pointers and memory applications, release

When the pointer is defined, it is like having a piece of street sign. Different types of pointers will be used to point to different types of physical objects, just like the attraction class indicate points to an attraction, the ticket office specification pointing to the ticket office, these different types Signage (different types of pointers) are all whiteboards when they are just established, that is, their pointing is undefined, can't be used directly at this time.

example:

U8 DFD2_10CMD_CHECKERaseBlockSuccess (u16 * pp_adrbeginera)

{

......

Volatile U16 * PL_ADRESS_OF_ERASE

DO

{

VL_DATA1 = * PL_ADRESS_OF_ERASE; // Dangerous !!!

......

The pointer PL_ADRESS_OF_ERASE has not been pointed out to be used, dangerous.

To use the first job of these indications, the image or text of the corresponding type of the indicator is drawn on, such as "flying peak", while pointing the arrow of the sign pointing to the direction of the flying peak (this That is to assign the pointer and give it to the real thing). The value of changing the pointer is, for example, re-brushing the contents of the sign into "West Lake" while pulling the arrow of the sign. This means that the indicator of the attraction cannot be used to point to the non-attraction point unless the specified type is enforced. Sometimes, the pointing of the pointer should be established when it is used, such as establishing a pointer, letting it point to temporary cache, this cache is temporary, then it is necessary to build immediately, usually we can use Malloc to apply for a memory, pay attention to It is, the content of this memory is random, so it is necessary to clean it to use (using MEMSET, etc.). Similar processes are: We have to create a new attraction, first to apply for a land, the weeds on the land that have just been applied, then the signs will be brushed into "new attractions" and point the arrow to the new land Such another person can be processed by the indicator to find the corresponding land. A low-level error often happens: we have a whiteboard indicator, not pointing anywhere, but the programmer is very clear that the sign will be used to point to "new attractions". In the case where the land of the new attraction has not been applied, we issued a starting order, hoping that the bulldozer goes to the land of the new attraction, so dangerous situation happens! The arrow of the whiteboard indicator is currently referred to as uncertain (the point to the new pointer is random), and the bulldozer starts to remove it in accordance with this persistent point! This situation will lead to serious illegal operation in many operating environments!

If the memory pointed to by the pointer is dynamic application, the memory should be released while using it, and the content of the pointer should be set to NULL (equivalent to erase the indicator content, including its arrow pointing), so that the call It is found that the pointer is empty and reports the error and pause processing. Take the "New Attraction" indicator as an example. If the land of the new attraction has been recovered, the sign does not update, others continue to visit according to the pointing sign (such as the building), which will cause serious consequences!

The pointer is a survival, often we will establish a pointer to some local (such as functions or cycles), then the living cycle of these pointers is in the part, if the memory points to the application, There is no release before the end of the partial program, then the memory pointed to by the pointer is also occupied by the program. If the memory has not been pointed out by other pointers, the memory leakage causes the memory. Especially for a long run, you will apply for a memory every time you run this program, but there is no, soon, the memory will crash due to the application (in the Windows system, the physical memory is used up. Use the hard disk as a virtual memory, so it can also resist a while, but the system performance is rapidly declining), the memory application and the release mechanism are not smooth, and more memory will eventually lead to crash. Second, array superfound

If the length of the array is N, the array can be accessed is 0 ~ (n-1), which is often neglected due to carelessness.

example:

"MMS_UI_RETRIEVE_HNDLR.C", line 2320: Warning: C2914W: OUT-OF-BOUND OFFSET 32 IN Address

VOID MMS_UI_GET_MM_CONTENTS_CONF_HNDLR (...)

(* (text_file_names index)). File_name [fs_max_filename_size] = 0; // Should BE FS_MAX_FILENAME_SIZE-1 !!!!

Another reason is due to expansion or other modifications, leading to definition and use inconsistency caused a superior. The most common thing is to define an array to use macro to represent the length, while the places used in the program are directly used as a subscript, once the length of the array is changed, these are directly accessed by the number as an array of numbers. There will always be a problem, and the access range beyond the array will result in serious consequences.

example:

Hfd1sem.c

U32 HFD1_1InitstartMode ()

A_erasesecturector [type_16k] = a_addresssector [i] .v_addressbeginsector;

Relevant definitions:

#DEFINE NB_ERASE_Sector 0x02

GLOBAL U32 A_ERASESECTOR [NB_ERASE_SECTOR];

#define Type_64K 0x00

#define Type_8k 0x01

#define Type_16K 0x02

It can be seen that TYPE_16K may be subsequent upgrade added, but the number of elements of array a_erasesecture is not upgraded simultaneously, causing an array to access the superior.

Third, the function returns

1, should return without returning

Such errors are very dangerous, and the compiler will report WARNING to: Implicit Return In Non-Void function. If a function is not only using its function, if the call does not rely on its return value, the problem is not large, however, once the upper layer calls depend on its return value, it may be troublesome. In order to change the point of view, since it is designed to return the function, most cases are to rely on its return value.

example:

U32 MMS_UI_STRLEN (Const U8 * srcstring)

{

IF (srcstring [0] == 0x80)

{

/ * IT is a unicode * /

Return srcstring [1];

}

Else

{

/ * IT is usascii * /

Strlen (const char *) srcstring;

}

}

In this typical error example, the function needs to return the length of the string, but one of the conditional branches have forgotten to return a value, then call the function.

LEN = MMS_UI_STRLEN ((U8 *) & string_buf [0]);) is extremely thrilling!

Another situation is that it is returned in the program, but there is no return value:

example:

U16 * DSC0_46Filliconincoloriconbuf (...)

IF ((mv_u16bitmapxwidth == 0) || (MV_U16BITMAPYHEIGHT == 0))

Return;

However, the call to the above functions is to use the return value:

PU16IONBUFPTR = DSC0_46Filliconincoloriconbuf (...);

2, should not return back

This situation is a relatively small problem, and the function has no effect, but the design is displayed, the programming is rough.

3, return local variables

This is a more easily misfortune, and the results caused by run may be fatal. First we all know that the life cycle of local variables (including pointers) is partial and short, there are two cases when returning a local variable in the function: returning to local numerical variables, structural variables, etc., actually the variable The value returned, and the correct value was obtained. Another situation is to return a cache (such as a local string) in a function, often see the following error programs:

example:

Char * func ()

{

Char BUF [20] = {0x00};

CHAR * P = BUF;

INT I;

Sprintf (BUF, "0123456789987654321");

Return buf; // return p; // same !!!

}

WARNING will generate when compiled: Function Returns Address of Local Variable, that is, the address of the local variable is returned. Because once the function is exited, the local array BUF may be used as it, where the content is unsody. But usually this error is more concealed, the reason is to access the address returned by the returned address, the original part of the local array is not completely modified, sometimes it is complete. But we should be very clear that this is an incorrect error that must be guaranteed that the part is no longer able to determine if there is any content. The solution is to use an array that is long enough, or uses a dynamic application to obtain memory (call malloc).

4, pointer as parameters

When the pointer is used as a parameter, in addition to modifying the contents of the memory referred to by the pointer, we often think that the pointer itself will continue to be valid after the call is called, but the situation is not the case!

example:

Void RemoveSpecialHeader (char * p_src)

{

IF (p_src == null)

{

Return;

}

IF (p_src [0] == 0x0a)

{

P_src = p_src 1;

}

}

Char stranditbuf [] = "/ x0atext begin here ...";

Char * p_str = streoutitbuf;

Printf ("0x% 02x / n", p_str [0]); // show in hex format: 0xnn

RemoveSpecialHeader (P_STR);

Printf ("0x% 02x / n", p_str [0]); // show in hex format: 0xnn This program is to let function RemoveSpecialHeader () special first character string of incoming pointer P_STR, if Discover the character (modify the P_STR pointer). Parameters of the transmitted function RemoveSpecialHeader () are the value of the pointer of this P_STR. After entering the function, the function has a copy of P_STR, so it is intended to modify the value of P_STR, in fact, the value of this pointer copy, call RemoveSpecialHeader () After the end, the value of the pointer P_STR is not changed, and it is still pointing to the first element of Streditbuf, the result of the run (two print 0x0a) proves this. This case in which the incoming pointer in the function is in the function is in vain, like the modified variable.

Fourth, other common mistakes

1, Memcpy

The prototype of Memcpy is void * memcpy (void * out, const void * in, size_t n);

Its role is to copy N each byte to the OUT pointer to the OUT pointer. In our program, you often need to clear a memory all 0x00 and should use the MEMSET function. But the actual many places are wrong to call Memcpy, and this problem is that such problems will not be generated in the compilation phase, but the actual result is completely wrong.

example:

LK4DRIV.C

ColorWindowsHow ()

Memcpy (p1_windowdisplay-> windowstring, 0, sizeof (winstring));

The function here will begin to read some bytes from the place where the memory 0x00000000 is written, and write to the destination memory. In many operating systems, the access address of the memory is strictly restricted, and the obvious 0x00000000 is not the place where the user program can access, so the illegal operation will be caused in Windows, and the Unix will cause segmentation fault and it is forced to abort!

Similarly, Memcpy (DEST, '/ 0', Length) is also exactly the same error, the reason is where '/ 0' is actually 0x00, and the function will treat it as an address.

In addition, Memcpy (DEST, "/ X00", Length) is also problematic, "/ x00" as a string, itself has only one byte, plus an end value 0x00, this string is when compiling In the data segment of the user program (of course, there is no problem), the first address of the string will be copied when the call is called, but according to the LENGTH, it usually has to exceed the only one byte, and finally Copy a lot of hetero data that keeps followed behind the string.

Therefore, Memcpy is very dangerous from 0x00000000000000000000000000, which should be used:

MEMSET (DEST, 0X00, Length);

2, == and =

IF judgment misuse "=":

example:

Void MMS_UI_SAVE_IN_PENDING_HNDLR ()

if (Validity_Period = MMS_YES)

This error causes the variable that is only judged only and unconditionally, and a significant impact on subsequent procedures.

Note: Some conditions are special in terms of conditions, although the same warning is generated, but the design purpose is to assign variables, then determine if the variable is TRUE or FALSE. Especially when reading files, serial ports, network data, but this method is more confusing, it is not worth recommending, it is best to write two steps. Example: Condition in the first value and then judge

CONFIGURATION.C:

Static void setprop (...)

IF (P = (Property *) JAM_Malloc (Sizeof (property)))

{

......

}

The assignment is misused "==":

example:

No Side Effect in Void Context: ' == '

BOOL SMS0_4IF ()

Case if_saved_in_flash:

{

v_status == false; // shop be '='

......

}

This situation causes the value of the variable until the value has not been modified, and it will also have a major impact on the program.

3, the length of the needle

example:

Char Str [10];

Char * p = STR;

Sizeof (P)

Here, it is intended to take the length through the pointer P to the STR, but the fact is that SIZEOF (P) returns only the size of the pointer P itself (4), not the length of the content indicted to it.

4. Conditions judgment not (!) Misunderstanding with the counter (~)

When the value of the variable to be judged is 0:

~ 0 is like! 0, the condition is True, but once the variable value is not 0, for example! 2 is false, ~ 2 means to reverse the 0x02 positioning, so ~ 2 is TRUE. So! The misuse of ~ only has the same value of 0 after the value is true, and other situations are different!

example:

Static bool minute_right = false;

Void LK8_1UPDATETIME (...)

IF ((~ minute_right) && (Test_Minute_Times <4) && ((t_minute-u16true_minute) == 1)) {

TEST_MINUTE_TIMES ;

}

5, confused characters and strings

A character is generally one byte, defined by single quotes, and the string is enclosed in double quotes. The length of the character is very obvious, and the length of the string is always the preset character of the preset character when defined. This is often confused when the character string contains a single visible character. Everyone must distinguish "0" (0x30 0x00), '0' (0x30), "/ x00" (0x00 0x00) and '/ 0' (0x00) concept .

example:

Dir2Sub.c ", Line 500: Warning: C2203W: NON-Portable - Not 1 Char in '...'

Void Dir2_7save_phone_book_data (...)

STRCHR (Ga_DirphoneNB, '* w')

Here, the second parameter of STRCHR is a character, and the actual situation is that two ordinary characters in single quotes (non-escape characters), which is quite increasing. If you want to find a string, the STRCHR function cannot be completed once, and the string should also be enclosed in double quotes.

Find a string:

STRPBRK - FIND Chars in String,

Eg. npos = strpbrk (straddr, "@:") 6, beyond range

Example: 16-bit value assignment to 8-bit variable

U32 MAT73_04MAPCOLORLCD (...)

U8 VP_BGCOLOR = 0xfff;

Similar questions may be that variable type changes or upgrade data lengths and forgetting upgrade variables, etc., consider when they are modified, may result in some errors.

For example, u8 vp_bgcolor = bgcolor_white; when defining BGColor_White, the BGCOLOR_WHITE expanded 16 bits when the upgrade modification, resulting in the original assignment.

In the use of strings, there is often an exceeding range, such as 15 bytes, causing the string that does not have a string end value 0x00, and the length is not specified without the length of the string. It has always been rolled out of the string until the latter memory appears, which is not small.

example:

Char * LK4_202GETMMMSSETTINGSTR (...)

Static ASCII VA_IPADDRESS [15] = "000.000.000";

Another situation is that a cache is only n bytes, but it is read from the byte that is more than n, or when writing it, it will result in unpredictable crashes.

example:

BlackJack.c

U8 Bufferptr [400];

Void DSP_Drawpstring (..., u8 * pstr, ...)

{

IF (* pstr == uni_header)

{

U16YPOS = 100;

Memcpy (BufferPtr, PSTR 1,400);

}

Else

{

Memcpy (BufferPtr, PSTR, 400);

}

}

Call:

U8 Btempstr [4];

......

DSP_DRAWPSTRING (..., btempstr, ...);

7, the variable is not assigned

This situation usually occurs in negligence, the following is two common situations:

example:

INT char_width; // does not value!

IF (conditiona)

{

CHAR_WIDTH = 16;

}

Else

{

IF (conditionb)

{

CHAR_WIDTH = 24;

}

// Else did not assign a value to char_width, causing negligence

}

IF (char_width == 16) ......

Use char_width, but at this time, it is possible that the value of char_width is uncertain.

example:

Int attrib1, attrib2; // no initial value!

Switch (SomeType)

{

Case aa:

{

Attrib1 = 12;

Attrib2 = 16;

}

Break;

Case BB:

{

Attrib1 = 12;

// Forgot to assign an Attrib2

}

Break;

}

// Use attrib2 here to cause consequences to be unpredictable

V. Skills and Tips

1. Get the unix command execution result Use nohup to save all the outputs of the command (program or shell directive) to the file, the default file name is Nohup.out, if the file already is existing, each time is accumulated.

Example: Output all the results of compile_all.sh to nohup.out files

Nohup ./compile_all.sh

The NOHUP command is not only the same, ">>" and ">" do not seem to redirect the standard error in the default state, while NoHUP can. 2, the array initialization initials all the elements in the array into 0x00, which is very simple, as long as the explicit sets the first element to 0x00, the compiler will automatically initialize other elements to 0x00. example:

Char straddress [50] = "/ x00"; // The entire string is initialized, each byte is 0x00

Note: If you want to use this method of specifying the first element value to initialize the value of the array is unreasonable, for example:

example:

Long ltotals [100] = {300}; // The entire array element will only be the first 300, the rest is 0

转载请注明原文地址:https://www.9cbs.com/read-123699.html

New Post(0)