C Programming Cultivation - It is recommended that beginners must see
What is a good programmer? Is it a lot of technical details? Or do you understand the underlying programming? Or is the programming speed is faster? I don't think it is. For some technical details and the underlying technology, as long as you see help, check the information can be found. For speed fast, as long as you make more, you will be able to happen. I think a good programmer should have the following qualities: 1. There is a spirit of research, diligent good, and give a non-three. 2, positive attitude, creative thinking. 3. The ability to actively communicate with people, there is team spirit. 4, modesty and cautious, arrogance and arrogance. 5, the code written is high. Including: Code stability, easy reading, standardization, easy maintenance, professional. These are the cultivation of programmers. Here I want to talk about "programming cultivation", which is the 5th point in the above. I think, if I want to know a author, I will see what he wrote. If I want to know a painter, I will see the drawing he draws. If I want to know a worker, I will see what he makes it. Similarly, if I want to understand a programmer, I want to first think that his program code, the program code can see a programmer's quality and cultivation, the program is like a work, qualified procedures The work must be a beautiful picture, a wonderful song, a pleasing novel. I have seen many programs, there is no comment, there is no narrow, the name of the variable name, etc.,,,, No, it is completely destroyed. They are said to be programs, but it is better to "encrypt" on the source program. This kind of programmer should be expelled, because he edited the value, It is far less than the value that needs to be maintained above. Programmers should have programmers, so afraid of tired, no time, but also to be responsible for their own procedures. I would rather want the programmer that is slow, technical, but there is a good writing program style, or the programmer of "destroying" skills. There is a saying that "the word is like a person", I want to see a programmer from the program. Because the program is a programmer's work, the quality of the work is related to the reputation and quality of the programmer. The "cultivation" good programmer must make good procedures and software. There is a idiom called "alone", meaning what you have to do very professional, very careful, if you have to be a "craft", it is a deep person, then, from a very simple work. It seems that you have the characteristics of "craftsman", I think it is not difficult to do a programmer, but it is not easy to do a "programmer". The programming is very simple, but it is difficult to compose quality procedures. I don't discuss excessive technology here, I just want to say something that is easy to ignore, although these things may be fine, if you don't pay attention to these subtle, then he will be very big. The impact of your entire software quality, as well as the implementation of the entire software, the so-called "Thousand Miles of Bius, Destroyed in Ant Accent". "Seeing the truth in the wealth", I can really embody the bottom of a program is just in these subtle. This is the programmer - programming cultivation. I summed up 32 "cultivation" on the program writing with C / C language (mainly C language). Through these, you can write a high quality program, and you will also let the human stains you have Stains, those who have seen your procedure will definitely say: "This person's programming is not bad."
------------------------ 01, copyright and version 02, indentation, space, wrap, blank line, align 03, program notes 04, functions [In] [OUT] Parameters 05, the return of the system call is determined 06, if statement pairs the error 07, the #ifndef 08 in the header file, allocates the memory 09 on the heap, the initialization of the variable 10, H, and C files Use 11, error information 12, common function, and naming number of named 14, function name, and variable name in the circulatory statement, the pass value of the variable name, the passage of the function, and modify the cultivation of the person program 16, put the same or near The same code forms function and macro 17, brackets in the expression, the number of Const 19 in the function parameters, the number of parameters of the function 20, the return type of the function, do not omit 21, the use of the GOTO statement 22, macro use 23, Static Use the code size 25 in the function, the use of TypeDef 26, for the constant declaration macro 27, do not perform order 29, ||, and &&'s statement to execute the order 29, try to use for for why , Please sizeof type instead of variable 31, don't ignore WARNING 32, writing Debug and Release version ---------------------- 1, copyright and Version ------- Good programmer gives yourself, each file, in note, copyright and version.
For C / C files, the file head should have a comment like this: / ******************************** **************************************** File name: network name: network.c ** file Description: Network Communication Function Set ** Creation: Hao Chen, February 3, 2003 ** Version Number: 1.0 ** Modify Record: ****************** *********************************************************** **** / and for functions, there should also be similar to such a comment: / * ============================= ============================================ ** function name: xxx ** parameter: ** Type Name [ IN]: descripts ** description: ** ** .............. return value: success TRUE, FALSE ** failure to throw an exception: ** author: ChenHao 2003/4 / 2 * ================================================== ================ * / Such a description can make people have a function, one file has a general understanding, which is very easy to read, and easy maintenance. benefit. This is a good start.
2, indent, space, wrap, blank line, alignment -------------- i) indentation should be done every program, as long as the program is programs, you should know This, but I still have seen the procedure that does not indent, or the procedure that is indent, if your company also has a programmer who writes the program, please open him without hesitation, and destroys the sin of the source Prosecution of him, but he still compensates that the mental loss fees for those who have read his procedures. Indent, this is an incumbent rule, and I will retrieve it, a indentation is generally a Tab key or 4 spaces. (Best use of Tab) ii) space. Does the space will give the program? No, effective use of spaces can make your program read more and pleasing. Not a pile of expressions are squeezed together. Take a look at the code below: HA = (HA * 128 * Key )% Tabptr-> size; ha = (ha * 128 * key )% tabptr-> size; there is a space and no space feeling different. In general, the statement is equipped between the individual operations, and when the function is called, it is equipped with each parameter. Such a banitary and non-added: IF ((HPROC = OpenProcess) {} == NULL) {== NULL) {== NULL) {== NULL) {== NULL) {== NULL) {} III) Retained. Don't write the statement on a line, this is very bad. Such as: for (i = 0; i '9) && (a [i] <'a' || a [i]> 'z')) Break; I copy, this is no space, no wrap What is the program written? Plus spaces and wraps. For (i = 0; i IF ((A [i] <'0' || a [i]> '9') && (a [i] <'a' || a [i]> 'z') How much is it? Sometimes, when the function parameters are more, it is best to go, such as: CreateProcess (Null, Cmdbuf, Null, Null, Binh, Dwcrtflags, Envbuf, Null, & SistartInfo, & Prinfo); Conditions The statement should also be wrap when necessary when necessary: if (CH> = '0' || CH <= '9' || CH> = 'A' || CH <= 'Z' || CH> = 'A' || CH <= 'z') iv) blank line. Don't spoil, the blank line can distinguish between different blocks, blocks, and best to add space lines.
Such as: HANDLE hProcess; PROCESS_T procInfo; / * open the process handle * / if ((hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid)) == NULL) {return LSE_MISC_SYS;} memset (& procInfo, 0, sizeof (procInfo)) Procinfo.idproc = PID; procinfo.hdproc = hprocess; procinfo.misc | = mscava_proc; return (0); v) alignment. Use the Tab keys to the declaration or comment of your variables, you will make your program look good. Such as: typedef struct _pt_man_t_ {int numProc; / * Number of processes * / int maxProc; / * Max Number of processes * / int numEvnt; / * Number of events * / int maxEvnt; / * Max Number of events * / HANDLE * Phndevnt; / * array of events * / dword timeout; / * time out interval * / handle hpipe; / * namedpipe * / tchar usr [maxusr]; / * user name of the process * / int Nummsg; / * Number of Message * / Int msg [maxmsg]; / * Space for intro process communicate * /} Pt_man_t; how? It feels good. Here mainly tells the story, if you write a pleasing code, the good-looking code will make people feel happy, read the code, not tired, work, neat program code, usually more welcome, more people. Now the hard disk space is so big, don't let your code squeeze together so they will complain that you abuse them. Ok, use "indentation, space, wrap, blank, align" to decorate your code, let them get a row of ordinary organs from there is no order.
3, program comments ------ Develop the habit of writing the program annotation, this is the work that each programmer must do. I have seen that thousands of lines, but there is no row of comments. This is like driving on the road, but there is no road sign. How long does it take? I don't know my intention, I have to spend a few times, I understand that this kind of people who waste others and their own time are the most compussia. Yes, you may say, you will write a comment, really? The writing of the comment can also see a programmer's skill. Generally speaking, you need to write a note at least in these places: The annotation of the file, the comment of the function, the comment of the variable, the comment of the algorithm, the program comment of the function block. Mainly to record what is your program? What is your intent? What is your variable used? and many more. Don't think about it, there are some algorithms that it is difficult or written. It can only be aimed. I admit that there is this situation, but you have to write it, just can train your own expression. The ability to express the technicians of the kind of technicians who are stuffy, you have a high technology, if you express your ability, your technology will not be able to get full. Because this is a team's era. Ok, say the technical details of several comments: i) I don't agree with the row bet ("//") than the block annotation ("/ * * /"). Because some old versions of the C compiler do not support row notes, for your program's portability, please try to use block comments. II) You may not be nested by the block annotation, then you can use the precompilation to complete this feature. Use the code enclosed in "#IF 0" and "#ndif", will not be compiled, and it can be nested. 4, function [in] [out] parameter ----------- I often see this program: funcname (char * str) {int LEN = strlen (str); ..... } char * getUsername (struct user * puse) {return PUSER-> name;} no! Please don't do this. You should first judge that the pointer to come in is empty. If the pointer passed is empty, then a big system will crash because of this small function. A better technology is to use assertions (Assert), here I don't have much to say these technical details. Of course, if it is in C , reference is much better than the pointer, but you also need to check each parameter. When writing a function of parameters, the primary work is to perform all the parameters that come in and perform legality checks. The parameters of the outgoing parameters should also be checked. This action should of course be external to the function, that is, after the call is completed, the value it will be checked. Of course, check will be wasted, but for the entire system, "illegal operation" or "Core Dump" error, how many spends this time is still worth it.
5, the return to the system call to determine -------------- Continue the previous one, for some system calls, such as opening the file, I often see that many programmers return to FOPEN not Do any judgment, use it directly. Then find that the content of the file is not read, or you can't write it. Or just judge: fp = fopen ("log.txt", "a"); if (fp == null) {printf ("error: open file error / n"); return false;} There are still many others. For example: Socket returned to the Socket number, Malloc returned by Mall. Please judge what these system calls returned. 6, the IF statement to the error process ----------- I saw you said, this is good to say. Still first look at a program code. IF (CH> = '0' && ch <= '9') {/ * Normal processing code * /} else {/ * Output error message * / printf ("error ... / n"); Return (False); this structure is very bad, especially if "normal processing code" is long, it is best not to use ELSE for this situation. First judge the error, such as: if (CH <'0' || CH> '9') {/ * Output Error message * / printf ("error ... / n"); return (false);} / * Normal processing code * / ... this structure is not very clear? Highlight the wrong condition, let others use your function, you can see unhanectation conditions, so you will be more conscious.
7, #ifndef in the header file ---------- Don't ignore the #ifndef in the first part, this is a very critical thing. For example, you have two C files, both C files include the same header file. When compiling, these two C files should be compiled into a run file, so there is a problem, a large number of statements conflicts. Still put the contents of the header files in #1ndef and #ndif. Whether your header will be referenced by multiple files, you have to add this. The general format is this: #ifndef
8, allocate memory on the pile --------- Many people may not understand the "stack stack" and "stack of HEAP" on memory allocation. People who include some barborses are not understanding these two concepts. I don't want to say more about these two things. Simply put, the memory system allocated on the Stack is automatically released, the memory allocated on the HEAP is not released, even if the program exits, the memory is still there. Stack is typically static allocation of memory, and HEAP is generally dynamically allocated. The memory allocated by the Malloc system is allocated from the heap. The memory allocated from the pile must be released by himself. Use free release, or the term - "Memory Leak" (or "Memory Vulnerability") - Memory Leak. Thus, the system's allocated memory will be less and less Mallo, until the system crashes. Let's take a look at the difference between "stack memory" and "stack memory". Stack memory allocation ----- char * allocstrfromstack () {char pstr [100]; return pstr;} 内 分 ----- char * allocstrfromheap (int LEN) {char * pstr; if (len <= 0 Return Null; Return (Char *) Malloc (LEN);} For the first function, the internal presence of the PSTR is released when the function returns. So the return of the char * is nothing. For the second function, it is allocated from the heap, so even if the program is exited, it is not released, so the memory returned by the second function is no problem, which can be used. But must call free release, otherwise Memory Leak! The distribution of memory is easy to cause memory leaks, which is the largest "gith" of C / C . If your program is stable, then Do not appear Memory Leak. So, I still have to pay a thousands of people here, be careful when using the Malloc system function (including Calloc, Realloc). Remember to have a service application on UNIX, there are a few hundred C files compiled, run a good test, etc., the system is Down every three months, and many people can't find the problem. . I have to manually restart the system every two months. This problem is that MeMery Leak is strange, and this problem in C / C will always happen, so you must be careful. A Rational's Detection Work - Purify, you can help you test your programs do not have memory leaks. I promise that the programmer of many C / C projects will have some cold in Malloc or New. When you use Malloc and New, there is a light tight and fearful feeling, you have this kind of cultivation. For Malloc and Free operations: 1) Pairing, there is a malloc, there should be a free. (C corresponds to new and delete) 2) Try to use on the same layer, do not like the above, Malloc in the function, and free outside the function. It is best to use these two functions on the same call layer. 3) Malloc allocated memory must initialize. The pointer behind free must be set to NULL. Note: Although the current operating system (such as Unix and Win2K / NT) have process memory tracking mechanism, that is, if you have released memory, the operating system will help you release it.
However, the operating system still does not release all the memory of Memory Leak in your program, so it is best to do this work. (Sometimes I don't know anything, there is a Memory Leak, and I find a non-sea cut pin in the code of millions of rows. Rational has a tool called Purify, which may be good to check the Memory Leak in the program. 9, the initialization of the variable -------- Joined the above, the variable must be initialized and reused. The C / C compiler will not help you initialize like Java, all need you, if you use no initialized variables, the result is unknown. Good programmers have never initialized the variables before using variables. Such as: 1) MemSet clear operation is performed on the memory allocated by Malloc. (You can use the Calloc assigning a total memory) 2) Initialize the Struct or array assigned on some stacks. (It is best to clearly), but also said that it is back, initialization will also cause a certain overhead of the system running time, so don't initialize all variables, this is meaningless. A good programmer knows which variables need to be initialized, which is not required. Such as: The following situations are not required. Char * pstr; / * A string * / pstr = (char *) malloc (50); if (pstr == null) exit (0); strcpy (pstr, "hello wrold); but if it is one of the following The situation is preferably initialized. (The pointer is a dangerous thing, must initialize) Char ** pstr; / * A string array * / pstr = (char **) Malloc (50); if (pstr == null) exit (0); / * Make pointers in arrays to null * / memset (pstr, 0, 50 * sizeof (char *)); and for global variables, and static variables, they must be initialized when they declare. Because you don't know where it will be used for the first time. So the initial use before use is more unrealistic, so you must initialize them when declaring. Such as: links * plnk = null; / * For global variables PLNK initialized to null * /
10, how to use H and C files --------- H files and C files? In general, the H file is a Declare, which is define in the C file. Because the C file should be compiled into the library file (Windows is .Obj / .lib, UNIX is .o / .a), if others want to use your function, then reference your H file, so h file Generally, variables, macro definitions, enumeration, structures, and function interfaces, just like an interface description file. The C file is a detail. The maximum use of H files and C files is declaration and implementation. This feature should be recognized, but I still see some people like to write the function in the H file, this habit is very bad. (If it is C , for its template function, only the implementation and declarations in the VC are written in a file because the VC does not support the export keyword). Moreover, if the implementation of the function is written in the H file, you have to add the dependency of the header file in makefile, which will make your makefile unregistered. Finally, there is a place that is most important to pay attention to: the global variable with initialization should not be put in the H file! For example, there is a structure for processing error information: char * errmsg [] = {/ * 0 * / "no error", / * 1 * / "open file error", / * 2 * / "failed in sending / received a message ", / * 3 * /" bad arguments ", / * 4 * /" memeroy is not enough ", / * 5 * /" service is down; try limited, / * 6 * / "unknow information", / * 7 * / "a socket Operation Has Failed", / * 8 * / "permission Denied", / * 9 * / "Bad Configuration File Format", / * 10 * / "Communication Time Out", ...... ...}; Please don't put this thing in the header file, because if your header is used by 5 functions (.lib or .a), he is linked in this 5 In .lib or .a, if your program uses a function in these five functions, and these functions have been used in an error message. Then this information will have 5 copies existing in your executter. If your Errmsg is big, and your execution file will become bigger. The correct way to write it into the C file, and then add external declaration on each of the Errmsg's C file headers, let the compiler will take him when the compiler is in the link. Come, there will only be an errmsg exists in the execution file, and so that this is good to package. The most crazy thing I have encountered is that in my target file, this errmsg has a total of 112 copies, and the execution file is about 8m.
When I put errmsg in the C file, and after more than a thousand C files with Extern declaration, all the function library files decreased by about 20%, and my executive file was only 5m. There is a little less than 3m. [Remark] ----- There is a friend to tell me, this is just a special case, because if errmsg exists in multiple copies in the execution file, speed up the program is running speed, the reason is that multiple copies of errmsg will make the system The memory change is reduced and the efficiency is improved. There is only one errmsg we mentioned here. When a function is to use Errmsg, if the memory is far apart, it will generate a change, but the efficiency is not high. This statement is not reasonable, but in general, for a relatively large system, errmsg is relatively large, so that the copy caused the size of the execution file to become large, not only adding the system loading time, but also a program in memory More page. For ERRMSG such data, in general, it will not be used frequently when the system is running, so the memory switching is not frequent. Under the trade-off, there is only one efficiency of Errmsg. Even if the data like LogMSG is frequently used, the operating system's memory scheduled algorithm will make such frequently used pages, so there will be no memory change issues 11, error information processing --- ------ Do you handle error information? Oh, it is not a simple output. Look at the following example: if (p == null) {printf ("Err: The Pointer is Null / N);} Say goodbye to the programming of the student era. This programming is very disadvantageous for maintenance and management, error information, or prompt information, should be unified, not like the above, write into a "hard coded". Article 10 describes a part of this in this regard.
If you want to manage the error message, you have the following processing: / * Declaration error code * / #define err_no_error 0 / * no error * / #define err_open_file 1 / * Open file error * / #define err_send_mesg 2 / * sending a message error * / #define ERR_BAD_ARGS 3 / * Bad arguments * / #define ERR_MEM_NONE 4 / * Memeroy is not enough * / #define ERR_SERV_DOWN 5 / * Service down try later * / #define ERR_UNKNOW_INFO 6 / * Unknow information * / #define ERR_SOCKET_ERR 7 / * Socket operation failed * / #define ERR_PERMISSION 8 / * Permission denied * / #define ERR_BAD_FORMAT 9 / * Bad configuration file * / #define ERR_TIME_OUT 10 / * Communication time out * / / * declaration error message * / char * Errmsg [] = {/ * 0 * / "no error", / * 1 * / "open file error", / * 2 * / "failed in sending / receiving a message", / * 3 * / "bad arguments" , / * 4 * / "memeroy is not enough", / * 5 * / "service is down; try limited", / * 6 * / "unknow information", / * 7 * / "a socket Operation HAS Failed ", / * 8 * /" permission denied ", / * 9 * /" bad configuration file pattern ", / * 10 * /" communication time out ",}; / * declaration error code global variable * / long errno = 0; / * Print the error message function * / void perror (char * info) {if (info) {printf ("% s:% s / n", info, errmsg [errno]); return;} printf ("Error :% s / n ", errmsg [errno]);} This is basically ANSI's error handling detail, so you can do this when you have an error in your program: BOOL Checkpermission (CHAR * UserName) {IF STRCPY (username, "root")! = 0) {errno = err_permission_denied; return (false);
} ...} main () {... if (! ") {PERROR (" main () ");} ...} One is a common, and some error message processing, this is advantageous The same error has the same information, the unified user interface, and does not fail because the file is opened, the A programmer has an information, and the programmer has an information. And do this, it is very easy to maintain. The code is also easy to read. Of course, the object must be reversed, nor is therefore necessary to put all the outputs in Errmsg, extracting more important error messages or prompting information is the key, but even though, this also includes most of the information. 12. Common functions and cyclic statements in the calculated quantity ---------------- Look at the following example: for (i = 0; i <1000; i ) {getLocalHostName Hostname); ...} getLocalHostname means that it takes the current computer name, in the cyclic body, it will call 1000 times. How much do this have no efficiency. This function should be taken to the cyclic body, which is only called once, and the efficiency has been greatly improved. Although our compiler will optimize, we will get the unchanged thing in the cycle, but you believe that all compilers will know which constant? I think the compiler is unreliable. It is best to do it yourself. Similarly, for non-variables in common functions, such as: getLocalHostName (Char * name) {char fullcname [] = "getLocalHostName"; sys_log ("% s begin ...", funcname; ... sys_log "% s end ...", funcname);} If this is a frequently called function, you must allocate memory for each call. This overhead is very big. State this variable into static, when the function is called again, it will save the overhead of the distribution of memory, and the execution efficiency is also very good.
13, function name and variable name ------------ I see many programs to name the variable name and function name, especially the variable name, what A, B, C, AA, BB, CC, what FLAG1, FLAG2, CNT1, CNT2, which are also a behavior without "cultivation". Even good comments. A good variable name or a function name, I think there should be the following rules: 1) intuitively and can be spent, and hope that "decoding" will not be "decoded". 2) The length of the name should be the shortest length, but also to maximize its meaning. 3) Don't write all over, don't lower your lowercase, you should write, such as: getLocalHostName or useeraccount. 4) You can be short-handed, but you have to understand, such as: ErrorCode -> Errcode, ServerListener -> Servlisner, Useraccount -> USRACCT, etc. 5) In order to avoid the full bureau function and variable name conflict, you can add some prefixes, usually the module is referred to as a prefix. 6) The global variable is unified to add a prefix or a suffix, let people see this variable knows that it is global. 7) Name the function parameters in Hungarian nomenclature, local variables. But still have to adhere to the principle of "Wangwen Business". 8) Maintain consistent with standard libraries (such as: STL) or development libraries (such as: MFC). 14, the pass value of the function and the pointer ------------ When the function is transferred, when it is incorporated into a non-const, it means that the pointer to modify this pointer in the function. Refers to data in memory. If it is a pass value, then how to modify this value inside the function, it also affects the value that is not passed, because the pass value is only the memory copy. what? You said this feature, you understand, ok, let's take a look at the following routines: voidgetversion (char * pstr) {pstr = malloc (10); strcpy (PSTR, "2.0");} main () {char * ver = null; getversion (Ver); ... free (ver);} I assure that something like this is the most important mistake of a novice. The program is in vain through the function getversion to the pointer VER VER VER, but this method does not work at all, the reason is - this is the pass value, not a pointer. You may argue with me, when I divide the pointer? Take a closer look, in fact, what you are passing is that the pointer is actually in the value.
15. Modify the cultivation of others ----------- When you maintain the procedure of others, please don't delete or modify the existing program very residual. I often see that some programmers modify the expression or statement directly on others. When modifying others, please do not delete someone else's programs. If you think that others' programs are not correct, please comment, then add your own handlers, you can't know 100% know the intentions of others, so You can recover, please do not rely on CVS or SourceSafe this version control software, or you want to see you the intentions and steps you modify on the source code. This is when the program maintenance, a cultivated programmer should do. As shown below, this is a better modification: / * * ----- Comment by Haoel 2003/04/12 ------ * CHAR * P = (char *) Malloc (10) * MEMSET (P, 0, 10); * / / * ------ Added by Haoel 2003/04/12 ----- * / char * p = (char *) Calloc (10, Sizeof Char ); /* ---------------------------------------- */ ...of course This approach is to use when software maintenance, such a method, can make it easy to maintain the action and intentions of the previous code change, and this is also a respect for the original author. Modify someone else's programs in the "Note - Add" manner, it is better to delete the procedures directly. 16, form the same or nearly the same code to form a function and macro -------------------- Some people say, the best programmer is the most like "lazy" program. There is no reason. If you have some program's code snippet, or just the same, put them in a function. And if this code is not much, and it will be used frequently, you still want to avoid the overhead of the function call, then write him into a macro. Don't let the same code or functional code exist in multiple places, or if the function changes, you will modify several places, this will bring huge trouble to maintenance, so " Change hundreds of changes, or form a function or macro.
17, brackets in the expression --------- If you are more complex expressions, you are not very clear, even if you are very clear, please add Brackets, otherwise, when you read the procedure yourself, you will look at it and look at it. In order to avoid this "misunderstanding", there is also a clearer, or add parentheses. For example, take the address for a member of a structure: GetUserage (& (UserInfo-> Age)); Although, & userInfo-> AGE, -> operator's priority, plus a bracket, will make people look at it Understand what your code mean. For example, a long condition determination: IF ((CH [0]> = '0' || CH [0] <= '9') && (CH [1]> = 'a' || CH [1 ] <= 'z') && (CH [2]> = 'a' || CH [2] <= 'z')) Braces, plus spaces and wraps, your code is not easy to read ? 18, constations in the function parameters ----------- For some of the pointer parameters in some functions, if you read only in your function, use const to modify it, so that others read your function interface. When you know that your intent is [in], if there is no const, the parameter represents [IN / OUT], pay attention to the Const use in the function interface, facilitating the maintenance of the program and avoids some errors. Although const char * p, const char * p, there is no, because your statement is not constant, the content of the pointer can be changed, because the compiler will force the conversion, but plus such a Description, facilitating the reading and compilation of the program. Because in C, a Warning will be reported when modifying the memory pointed to by a const pointer. This will cause the programmer's attention. C is very strict, so much more use of C , using const, constant member functions, constant variables, which will make your code and your program more complete and easy to read. (I will not say more about C constant)
19. The number of parameters of the function (more use structure) ----------------- The number of parameters of the function is not too much, in general, 6 or so Many function parameters will make the people who read the code look very dizziness, and they are not conducive to maintenance. If there are many parameters, please use the structure to deliver parameters. This makes it easy to clean the data package and the simplicity of the program. It is also beneficial to use the function, because if your function is a lot, such as 12, the caller is easy to make the order and number of parameters, while using the structural struct to transfer parameters, you can regardless of the parameters. Moreover, the function is easily modified. If you need to add parameters to the function, you don't need to change the function interface, just change the internal processing of the structure and function, and this action is transparent to the program of the call function.
20, the return type of the function, don't omit -------------- I don't pay attention to the type of function returning when you see a lot of program write functions. If a function does not return a value, please add Void's modification in front of the function. And some programmers are lazy, and what is not modified in the return of Int (because if not modified, the default returns int), this habit is very bad, or for the eEl of the original code, plus int. Therefore, the return value type of the function is not omitted. In addition, for Void's functions, we will often forget return, because some C / C compilers are more sensitive, will report some warnings, so even void's function, we should best add Return's statement internally. This contributes to the compilation of the code. 21. The use of GOTO statement -------- N years ago, a generation of Software developed - Dijkstra said: "Goto Statment is Harmful !!", and recommends canceling goto Scriptures. Because the goto statement is not conducive to the maintenance of the program code. Here I also strongly recommend not using the goto statement unless the following situation:
#define free (p) f (p) {/ free (p); / p = null; /} main () {char * fname = null, * lname = null, * mname = null; fname = (char *) Calloc (20, SIZEOF (CHAR)); if (fname == null) {goto errhandle;} lname = (char *) Calloc (20, sizeof (char)); if (lname == null) {goto errhandle;} MNAME = (char *) Calloc (20, sizeof (char)); if (mname == null) {goto errhandle;} ... errhandle: free (FREE); Free (MNAME) ReportError (err_no_memoey);} Only in this case, the GOTO statement will make your program easier to read and easier to maintain. (This structure is also encountered when setting the cursor operation in the database with embedded C.
22, the use of macro ------ Many programmers don't know what it means to "macro" in C? Especially when the macro has parameters, it often confuses the macros and functions. I want to talk about "macro" here, the macro is only a definition. He defines a statement block. When the program is compiled, the compiler first wants to perform a "replace" source of the source and put the macro. Replace the macro defined statement, just like text files. This action term called "macro" use macro to compare "danger", because you don't know what the macro will look like. For example, the macro below: #define max (a, b) A> B? A: b When we use macro this way, there is no problem: max (num1, num 2); because the macro is turned into Num1> Num2? Num1: Num2; However, if it is called, MAX (17 32, 25 21);, the error occurs when compiling, the reason is that the macro show becomes: 17 32> 25 21? 17 32: 25 21 , Wow, what is this? Therefore, when the macro is in use, the parameters must be added with parentheses, and the example described above is changed to solve the problem as follows. #define max ((a), (b)) (a)> (b)? (a) :( b) Even so, don't this macro still have bug, because if I call MAX (i , J ) After this macro, I and J were accumulated twice, this is never what we want. So, in the use of macro, you should also be careful, because the result of the macro show is difficult to make people expect. And though, the macro's execution is quickly (because there is no overhead of the function call), but the macro will rise to the source code, so that the target file size is large, (such as: a 50-row macro, 1000 places in the program) After the macro show will be very good after the opening), the reverse cannot make the program to perform faster (because the execution file is getting bigger, the runtime system is frequently changed). Therefore, it is necessary to use a function when deciding is a function. 23, Static's use -------- static keyword, expressed "static", in general, he will be used frequently for variables and functions. A Static variable, in fact, global variable, but he is a global variable with a role. For example, Static Variables in a function: char * getConSumerName () {static int CNT = 0; .... CNT ; ....} The value of the CNT variable will increase with the function's call time, the function exits, CNT The value still exists, just CNTs can only be accessed in a function. The CNT's memory will only be assigned and initialized when the function is first called. Each time you enter the function, it is not assigned to STATIC, and the last value is used directly.
For some constants within the frequently invoked functions, it is best to declare to static (see Article 12) but the maximum use of Static is not here, the maximum control of the role, if a function or one is The global variable is declared as static, then this function and this global variable will only be accessed in this C file. If other C files call the function in this C file, or use the global (with extern Keywords) will occur when links. This feature can be used for data and program confidentiality. 24, the code size in the function ---------- A function completes a specific function, in general, the code in a function should not exceed 600 rows, the less good, the best The function is generally within 100 lines, and the grandson of the 300 lines is almost. There is evidence that the code in a function is more than 500 lines, and there will be the same or similar code as other functions, that is, you can write another function. In addition, the function is generally a specific function, and millions are more different in a function. The function of the function is, the better, on the one hand, it is conducive to the easy-to-readability of the function. On the other hand, it is more conducive to the maintenance and reuse of the code. The more functions, the more the function is, the more probably provide services, that is, The more commonality. Although the call will have certain overhead, it is worthwhile to increase the overhead of the software.
25, use of typedef -------- TypedEf is a keyword for the type of alias. Don't read it, it will have a good role in your code. For example, there is no BOOL in c, so some programmers use int, some programmers use Short, which will be more confusing, preferably using a typedef, such as: typedef char bool; general, a C Be sure to do some work in the project, because you will involve cross-platform, different platforms will have different word lengths, so using pre-compiled and typedef allows you to maintain your code, as shown below: #ifdef SOLARIS2_5 typedef boolean_t BOOL_T; #else typedef int BOOL_T; #endif typedef short iNT16_T; typedef unsigned short uINT16_T; typedef int iNT32_T; typedef unsigned int uINT32_T; #ifdef WIN32 typedef _int64 iNT64_T; #else typedef long long iNT64_T; #endif typedef Float float32_t; typedef char * string_t; typedef unsigned char BYTE_T; typedef Time_t Time_t; typedef int32_t pid_t; other specification using TypeDef is the best use of Typedef when structural and function pointers, which also benefits the program's easy reading and Maintainability. Such as: typedef struct _hostinfo {HOSTID_T host; INT32_T hostId; STRING_T hostType; STRING_T hostModel; FLOAT32_T cpuFactor; INT32_T numCPUs; INT32_T nDisks; INT32_T memory; INT32_T swap;} HostInfo; typedef INT32_T (* RsrcReqHandler) (void * info, JobArray * jobs , Allocinfo * allocinfo, alloclist * alloclist); C is also very easy to read: typedef carray hostinfoarray;, when we use it to define variables, it will be very easy to read. Such as: hostinfo * phinfo; rsrcreqhandler * prsrchand; Easy to readiness in this way, is very obvious in the parameters of the function. The key is that after using Typedef, almost all procedures in almost all programs are so simple and clear, and it is easy to maintain. This is the key to TypedEf.
26, declare the macro for constants -------- It is best not to appear digital "hard coded" in the program, such as int user [120]; declares a macro for this 120. Declaring a macro for all such constants that appear in the program. For example, Timeout time, the maximum number of users, and others, as long as it is constant, it should be declared into a macro. If, suddenly appear in the program, for (i = 0; i <120; i ) {....} 120 is? Why is it 120? This "hard coded" not only makes the program very read, but also makes the program very bad, if you want to change this number, you have to make changes to all programs, this is a person who modifies the program. Very big pain. So I still declare a constant into a macro, so that it is changed, and it is also good to read. #define max_usr_cnt 120 for (i = 0; i ....} This is easy to understand the intention of this program. Some programmers like to declare global variables for this variable, in fact, global variables should be as small as possible The global variable is not conducive to the package, which is not conducive to maintenance, and has a certain overhead of the program execution space. If you accidentally change the system, resulting in a problem of speed efficiency. So, a macro, you can exempt the global variable Overhead, there will be speed advantages.
27, don't define the semicolon for the macro ----------- There are many programmers who don't know if they want to add a division when they define, sometimes they think that macro is a statement, should be added. This is wrong. When you know the principle of macro, you will agree that I will not define the semicolon for the macro. Look at an example: #define maxnum 1024; This is a semicolon macro, if we use: HALF = MaxNum / 2; if (Num
IF (SUM> 100 && ((fp = fopen (filename, "a"))))! = null) {fPrintf (fp, "warring: it beyond one hundred / n"); .....} fprintf (FP , "SUM IS% ID / N", SUM; Fclose (FP); Original intention, if SUM> 100, write an error message to the file, in order to be convenient, it is written together, so If SUM <= 100, the operation of opening the file will not do, Final, FPRINTF and FCLOSE will find unknown results. For example, if I want to judge whether a character is content, I have to judge that the string pointer is Not empty (NULL) and its content can not be empty, one is an empty pointer, one is empty content. I may write this: if ((p! = Null) && (Strlen (p)! = 0) Therefore, if P is NULL, Strlen (P) will not be executed, so Strlen will not "illegally operate" or a "core dump" because of an empty pointer. Remember a point, conditional statement In the middle, not all statements will be executed, when your conditional statement is very much, this should be particularly paying. 29, try to use for for while --------------- basically Said, for can complete the while, I recommend trying to use the for statement, instead of using the While statement, especially when the cyclic body is large, the advantage is reflected. Because in For, the initial, At the end of the conditions, the promotion of the cycle is together, you look at this is what kind of loop. Just out of the school's procedures usually like this: p = phead; while (p) {... .. P = P-> Next;} When the whip of the state is bigger, your program will be difficult to read, use for more: for (p = PHEAD; P; P = P-> Next) {. In a glance, you know the beginning of this cycle, the conditions, and the promotion of the cycle. Come about what this cycle is to do? And the program maintenance comes easy, don't have to be like While, in a editor Upper and down.
30, please sizeof type instead of variables ------------- Many programmers in using SizeOf, like the SizeOf variable name, for example: int Score [100]; char filename [20]; struct userInfo USR [100]; When the number of variable names of SizeOf, the correct result is returned, so many programmers start the SIZEOF variable name. This habit is very good, but I still recommend a SIZEOF type. I saw this program: pscore = (int *) malloc (subject_cnt); Memset (pscore, 0, sizeof (pscore)); ... At this time, SizeOf (PSCORE) is 4 (length of the pointer) Not the entire array, so MemSet cannot initialize this memory. For the easy-to-read and easy maintenance of the program, I strongly recommend the type instead of variables, such as: SIZEOF (INT) * 100 / * 100 int * / for filename: sizeof (char) * 20 / * 20 char * / For usr: sizeof (struct userinfo) * 100 / * 100 UserInfo * / like this code is easy to read? I don't think it's mean at a glance. Another point, SIZEOF is generally used to distribute memory, and this feature can reflect its advantages in a multi-dimensional array. For example, give a string array allocated memory, / ** assign a 20 string, * memory * / char * p; / * / * = (char * p; / *) **) Calloc (20 * 100, sizeof (char));
/ ** Correct allocation method * / p = (char **) Calloc (20, sizeof (char *)); for (i = 0; i <20; i ) {/ * p = (char *) Calloc 100, sizeof (char)); * / p [i] = (char *) Calloc (100, sizeof (char));} (Note: The above statement is commented out, is wrong, by dasherest friends Finger, thank you) For the easy reading of the code, save some judgments, please pay attention to the methods of these two allocations, there is essentially.
31, don't ignore WARNING ---------- For some warning information, please don't ignore them. Although these Warning does not hinder the generation of target code, this does not mean that your program is good. By, it is not the process of compiling success. It is correct. The success of the compilation is just the first step in the Long March, and there is a big wind and big waves waiting for you. Starting from the compiler, not only correct each Error, and also correct each Warning. This is a cultivated programmer. In general, some warning information on one side is common: 1) declare unused variables. (Although the compiler does not compile this variable, it is still an annotated or deleted it from the source program) 2) Use the firing declaration. (Perhaps this function is in other C files, this warning occurs when compiling, you should use the extern keyword to declare this function) 3) No to convert a pointer. For example, the pointer returned by Malloc is Void. You didn't turn it into your actual type and alarm, or manually in the previously converted it) 4) Type down. (For example: float f = 2.0; this statement is the warned, compile will tell you that you are trying to turn a double to float, you are casting a variable, do you really do this? Or add one after 2.0 f, otherwise, 2.0 is a double, not FLOAT), no matter what to say, the compiler's Warning should not underestimate, it is best not to ignore, a program is doing, let alone a few small Warning?
32. Writing the debug version and the release version of the program ---------------- The program must have many programmers plus debugging information during the development process. I have seen many project groups. When the program is ended, the commissioning information in the program is launched, why? Why not build two versions of target code like VC ? One is a debug version, one is release. Those debugging information is so precious, and it is also very valuable during the future maintenance process. How can I say deletion? With the pre-compilation technology, the debug function is declared as shown below: #ifdef debug void trace (char * fmt, ...) {...} # elelse #define trace (char * fmt, ...) # Endif, let all the programs use trace to output debugging information, only need to add a parameter "-ddebug" when compiling, such as: cc -ddebug -o target target.c, the pre-compiler discovers the Debug variable is defined You will use the trace function. And if you want to release it to the user, just need to cancel the "-ddebug" parameters, so all TRACE macros, this macro does not, so all Trace languages in the source program are replaced by empty. Two fell swoop, one arrow double carved, why not? By the way, two very useful system macros, one is "__file__", one is "__line__", indicate that the source file and line number, when you debug information or output error, you can use these two Macro, let you see your mistake, which file appears in the first few lines. This is very tube for large works made with C / C . In summary of 32, it is for three major destination - 1, the readability of the program code. 2. Maintainability of program code, 3. Stability and reliability of program code. If there is a cultivated programmer, you should learn to write this code! This is any kind of problem that wants to face the programming master, the programming master is not only strong, the foundation is good, and the most important thing is to have "cultivation"! Good software products are not just technologies, but more is the easier maintenance and reliability of the entire software. Software maintenance has a lot of workload flowers on the maintenance of code, the software's Upgrade, there is a lot of work spending on the organization of the code, so good code, clear, easy-to-read code, will give great reduction software Maintenance and upgrade costs.