C Style Standards for ECE-1021

(Last Mod: 27 November 2010 21:38:37 )

ECE-1021 Home


The largest single cost in the software industry is software maintenance - correcting, updating, and improving existing software. To keep these costs under control, it is vital that people other than the original programmer be able to readily interpret a piece of code. One of the biggest steps to ensure that this is possible is to require each programmer to adhere to a common set of standards, known as Programming Style Standards. Standardization is not limited to the software industry, imagine purchasing a replacement battery for your flashlight if all battery manufacturers did not adhere to common standards for terminal voltage, shape, or physical dimensions.

If you have studied the material regarding Common C Pitfalls, you have already been exposed to most of the guidelines which make up this set of standards. The purpose of this section is to summarize these guidelines in one place. Be aware that there is no guarantee that the example code in this section will display or print on your particular browser correctly as the format depends on how your browser displays HTML text. So if the code does not appear to conform to the standards as described, contact the instructor for clarification - this will also permit the instructor to try to modify the HTML code so that it displays correctly on your browser.

If your code does not conform to these standards, it will not receive full credit. In general, the amount that is deducted will depend on how flagrant and rampant the violation is and at what point we are at in the semester. The fact that your code runs and produces the correct values will not influence this. The fact that you can show that your code is in compliance with someone else's Style Standards will not influence this. 

There was a time when a good programmer could guarantee their job by writing solid code that was impossible to read - and hence they were the only one who could maintain it. Those days are long gone - today a programmer, no matter how good, that tries to make themselves "indispensable" by not adhering to their employer's Style Guidelines quickly finds themselves looking for a new employer.


Style Guidelines for ECE-1021

The guidelines are broken into three groups, those that are general in nature, those that relate to specific layout elements and which are organized in the order that they would typically apply in a given program, and those that are oriented toward preventing common logic errors.

  1. File Name
  2. Student Identifier
  3. Revision Numbers
  4. Line Length
  5. Comments
  6. End of Line Characters
  7. Indenting
  8. Unused Code
  9. Compiler Warnings
  10. File Layout
  11. File Header
  12. Documentation of Waivers
  13. Program Exit Values
  14. Pseudocode Synopsis
  15. Pseudocode Deviations
  16. File Inclusions (#includes)
  17. Unparameterized Macros
  18. Parameterized Macros
  19. Global Variables
  20. Variable Declarations
  21. Variable Names
  22. Variable Initializations
  23. Restrictions on use of break, continue, and goto statements
  24. Void Function Types
  25. Void Parameter Lists
  26. Function return Statements
  27. Function Order
  28. Function Length
  29. Function Prototypes
  30. Function Prototype Reference List
  31. Function Declaration for main()
  32. Integer vs. Floating Point Constants
  33. Integer vs. Floating Point Division
  34. Equality Comparisons
  35. Floating Point Equality
  36. Verification of File Open Operations

File Name

(INCLUDES CHANGES EFFECTIVE FALL 2004)

Synopsis

Required format:  [HW][_][SEC][ID][REV].[ext] 

Detail

Your source code file will adhere to the DOS 8.3 format in which the filename is at most eight characters and the extension is at most three characters. The reason is that many compilers are not able to accommodate long file names.

Furthermore, your file names will adhere to the following naming convention:

[HW][_][SEC][ID][REV].[EXT]

As an example, a student in Section 3 whose assigned student code is CODE submits the fourth revision of her source code for homework #5. Her file name would be:

5_3CODE4.c

Note the simple rule regarding case - the filename proper is all uppercase while the file extension is all lowercase. It is recognized and understood that the Windows operating systems do not give you firm control over the case of characters in a file name. The rule regarding case applies to other places you use the name, such as e-mail subject lines and the file headers themselves.


Student Identifier

Synopsis

Use your assigned four-character Student ID Code, all upper case, where directed.

Detail

You will be assigned a four letter identifier that is unique to you among all of the students taking this course this semester. Normally, that identifier will be the first three letters of your last name followed by the first letter of your first name (as shown on the official course listing). However, if two people would have the same identifier (even if they are in different sections) then at least one of them will be assigned a different identifier by the instructor(s). A list of identifiers will be available on the course website and, if not, you should confirm your assigned identifier with your instructor prior to making your first homework submission.

Unless told otherwise for a specific purpose, your four-character ID should always appear as all uppercase.


Revision Numbers

Synopsis

Your first submission should be Rev 0 and subsequent submissions, if any, should increment this number. 

Detail

The code that you submit for grading must have a revision number. The first file you submit should be Rev 0, meaning that there have been no revisions submitted. If you find it necessary to resubmit your code - for instance, you find a mistake and fix it prior to the submission deadline - then you need to increment the revision number by one.

This is important as the program that is graded will be the one with the highest revision number that is received by the deadline. If two have the same revision number, then the one that is graded will be the last one downloaded from the mail server - which may well not be the last one received by the mail server. If the wrong program is graded because you failed to increment your revision number, then you will have to console yourself with the knowledge that few people make that particular mistake twice.

Lest you be tempted to flood the grader with submissions - note that there is a penalty for not making sure that the code you submit is the code you want graded (since this almost always reflects lack of adequate pre-submission testing on your part). The revision number is also the number of points that will be deducted from your program's final score. But don't let this deter you from resubmitting code that fixes a problem you discover - it only costs you one point to do so and will almost always save you points in the long run.

If the file name format is not followed, including the use of the proper revision number, then (assuming the Grader catches it) your file name will be changed by the grader and the revision number used will be one greater than the revision number that should have been used had YOU corrected the problem. As the file processing becomes more automated, there are fewer opportunities for the Grader to catch and correct your mistakes. Furthermore, they are under no obligation to even attempt to do so. Pay attention to what you are submitting!

You might find it very helpful to include a much finer revision tracking process for your own use - this can be quite handy to let you keep track of changes that you make and allow you to go back to code that was working should you mess up your code while exploring an alternate approach. You are encouraged to do this, but please don't confuse that with the revision number discussed here - this number is specific to revisions of the submitted code.


Line Length

Synopsis

No line in a source code or header file is to exceed 75 characters in length. Tabs are considered three characters for the purpose of this rule.

Detail

Although the maximum number of characters per line in a text file is often considered to be eighty - to match the eighty character width of most DOS console displays - most text editors, especially those that come as part of a C development environment, do not restrict you to this limit. They may, in fact, have no intrinsic limit. While the C language certainly sets no limit, the long standing tradition has been to limit lines in source code to no more than 80 characters to prevent line wrapping - either when viewed on the screen or when printed out - which can make the code considerably more difficult to read.

However, it turns out that many e-mail programs cause word wrapping even within attached text files if the length of any line is too great. This appears to be a function of the sender's e-mail program. This can cause a program that you submit to work fine on your machine but not run on the grader's machine (nor would it run on yours any longer since the file has been modified). Experience has shown that if line lengths are kept to 75 characters or less that this is not a problem and, to prevent it from being a problem for the grader, this limit has been adopted as a Style Standard for this course.

If your code contains lines that are longer than 75 characters and it causes no problems, either in terms of being modified by the e-mail program or in terms of readability for the grader, then normally only a few points will be deducted (since it is a violation of the standards). But, if your code does not compile because lines greater than 75 characters in length are wrapped during the submission process, then the code will be treated like any other code that fails to compile.

If this problem should happen with your submission and you do not have any lines greater than 75 characters in length, then the grader will modify your code to remove these revisions and grade your submission without penalty the first time it happens. They will also inform you of the problem and you are expected to find a way to solve it - which usually entails checking out the settings of your e-mail software or simply using a different e-mail client but which may require that you use a line length shorter than 75 characters in future submission. Both the grader and the instructor will work with you to solve the problem, but the responsibility is yours.


Comments

Synopsis

Use ample comments to document your code - particularly the higher level logical tasks being performed.

Detail

Document your code with ample comments. If you have organized your code well, selected truly meaningful variable names and #define labels and been consistent in their use, your code will be largely self-documenting and you can focus on adding comments where they are most effective. Where they are especially appropriate is any place where your are doing anything complicated or out of the ordinary. If you devise a little trick to increase program performance, you should comment this portion especially well.

Another very good place to include comments is to copy the upper levels of your pseudocode description to label the section of code that implements that task.

Take note that the original ANSI C standards did not recognize the use of a double forward slash to indicate a comment that continues to the end of the present line (generally referred to as "end-of-line comments"). While most compilers quickly adopted this convention and while it is included in the original ANSI standard for C++, it was only adopted by the C language standard as part of the C99 version of ANSI/ISO C. Therefore, end-of-line comments are not going to be ANSI C compliant with many of the compilers you are likely to use - including the ones in this course. For this reason, this style of comment was previously not allowed in this set of Style Standards. However, since the course material now includes other non-ANSI compliant elements from the Borland Extensions in some programs, this restriction has been removed.

Should you discover that your compiler is suddenly complaining about your end-of-line comments (or about lines containing these comments or the lines immediately after them) then one thing to check is the compiler options to see if ANSI C is being enforced. How you do this is dependent upon your specific compiler.


End of Line Characters

Synopsis

Your files are to use the DOS/Windows end-of-line sequence which consists of CR/LF pairs (ASCII code 0x0D followed by ASCII code 0x0A).

Detail

DOS/Windows machines use a pair of ASCII codes to denote the end of a line in a text file. The first is a Carriage Return (ASCII code 0x0D) which moves the cursor to the start of the current line followed by a Line Feed (ASCII code 0x0A) which moves the cursor down one line. Unix machines, on the other hand, use a single Line Feed character with an implied Carriage Return. 

Like the line-length issue described elsewhere, some e-mail programs attempt to perform a translation between the DOS and the Unix conventions as the e-mail is submitted. Anecdotal evidence suggests that this mostly happens with AOL and online "free" webmail servers since the e-mail program is running on a Unix platform and the attachment is coming from a Windows platform. Unfortunately, some e-mail programs do not do a good job of this translation and the result is that the received file either follows the Unix convention or it follows the DOS/Windows with an extraneous CR or LF character. This either results in the submitted file being unreadable or appearing to be double spaced.

You can determine if you are likely to have this problem by e-mailing your program to yourself and examining the actual byte values appearing in the file. To do this, you need to read the file in binary mode in order to suppress all ASCII translations.

The software to process submitted files scans the source code header to determine if a non-standard  end-of-line sequence is used and inserts a comment in the report file as appropriate. No points will be deducted on the first submission exhibiting this problem, but future submissions will be penalized. The normal solution appears to be to use a different e-mail program to send your submissions.


Indenting

Synopsis

Indent code according to its level.

Detail

Code should be indented according to its level. This means that all statements that are controlled by a particular line of code should be indented more than the controlling line. The amount of each indent should be consistent, two spaces works well. Where braces are used, the open and close braces should be vertically aligned with the left of the controlling line with no text (including comments) directly between them. In other words, all statements contained in a brace-delimited block of code should be indented more than the braces. This makes the structure of the code very clear and allows for easier debugging since matching braces and the manner in which they nest is readily apparent.

Example (keep in mind that the following is HTML code and may not display the same on your browser) :

         int main(void)
         {
            for(i=0; i<100; i++) // Comment may follow a line
            {
                if(i%5)
                    /* Place comments at same level as code */
                    printf("%i is divisible by 5.\n", i);
                else
                {
                    printf("%i is not divisible by 5.\n", i);
                    i+=i%5;
                }
            }
            return(0);
        }

This is probably the single most frequent point of contention, especially with students that have some experience writing C code. Arguments can always be made for the pros and cons of one style option as opposed to another. But no matter how superior you feel your favorite indenting style is, don't allow yourself to lose sight of the fact that this is the style standard that your code will be graded against. If you choose to be adamant about using your preferred method that is fine with the grader - who will assume that you have equally decided to accept the point penalty associated with that choice.


Unused Code

Synopsis

Delete unused code - don't just comment it out.

Detail

Delete portions of code - called orphans - that serve no purpose. You will frequently use the code from one project as the starting point for another project. Likewise, you will frequently try various alternatives on how to implement a particular task or insert code used to test or debug your program as you develop it. Do not leave this unused code in the final version since it tends to make reading the code quite difficult.


Compiler Warnings

Synopsis

Ignore compiler warnings at your own peril.

Detail

The code turned in should generate no compiler warnings (or errors, but that is penalized heavily elsewhere) except as expected. The only expected warning using the Borland TurboC/C++ v4.5 compiler is the following: 

Linker Warning: No module definition file specified: using defaults

This warning is to let the programmer know that, if they wanted to use what is known as a module definition file, that it wasn't found and that the compiler is proceeding based on its internal default definitions. This is what you want, so you can safely ignore this problem.

Another place where you will get a compiler warning is if you are using a custom header file that has executable code in it. Because of how files are submitted in this course, we will only have one C file and one (if any) H file per program and so the header file may contain executable code in it. This warning may also be ignored without penalty.

If you have any warnings (including those above), points will be deducted unless you do two things:

1) Document the warning in your source code. The best way to do this is to copy and paste the warning into a comment immediately below the file header in a section entitled "Waivers".

2) Document why the warning is being waived - i.e., convince the grader that it is both reasonable to expect that the program will run properly despite the warning AND that it is not reasonable to make the additional effort to write the code so as to suppress the warning. You can expect this last part to be a hard sell, but not necessarily an impossible one. For instance, if you can satisfy the first condition - satisfy us that ignoring the warning is safe - and the reason you are not removing it is that you haven't found a way around it then we are more apt to not deduct points. In either case, we will show you how to get around it in the future.


File Layout

Synopsis

The order of the major elements in your source code file should conform to the following list.

Detail

The order that the key elements in the source code file should be in is as follows:

Occasionally, the structure of a program may require some elements to appear in a different sequence than the one indicated. If this is the case, make the smallest deviation to the prescribed sequence that you can and document the deviation in the Waivers section.


File Header

(INCLUDES CHANGES EFFECTIVE FALL 2004)

Synopsis

The use of the standardized header is mandatory in source code and header files. The same information must also appear at the top of pseudocode and flowchart files.

Detail

A standardized file header is required at the top of every source code and header file. The format can be found in the source code template.

This same information is to be included at the top of other documents you submit, although the format is not as critical. The easiest way to do this is usually to just copy the source code header and paste it into your other document and then modify it as needed.

Detailed Instructions:

PROGRAMMER: Your last name in all capital letters, followed immediately by a comma, followed by a single space and then by your first name (with only the first letter capitalized). This should be surrounded by double quotation marks with no additional spaces inside the quotes. Use the name listed in the Student Identifiers list as this is the name that you are registered under - when all is said and done, your grades have to be transferred to grade sheets provided by the school.

PROG_CODE: This is the four character Student Identifier assigned to you, in all upper case characters surrounded by double quotation marks with no additional spaces inside the quotes.

COURSE: This should remain unchanged as "ECE-1021"

YEAR: The four-digit calendar year that the semester is in, surrounded by parentheses.

TERM: Either "Fall", "Spring", or "Summer" as appropriate.

SECTION: Your section number surrounded by parentheses. Do NOT leave it as section zero as this indicates an instructor's code file. While this might sound tempting, keep in mind that instructors do not receive a grade for their code - and neither will you.

ASSIGNMENT: This should simply be the string "HW#X" where 'X' is replaced by the homework number (a hexadecimal digit, uppercase if applicable).

REVISION: The revision number surrounded by parentheses.

TITLE: You may place any suitable title here. It can be any length that does not exceed the line length limit on that line.

SUBTITLE: You may place any suitable title here. The assignment may direct you to include specific information on this line. It can be any length that does not exceed the line length limit on that line.

EMAIL: This should be the e-mail address, surrounded by double quotes with no additional spaces inside the quotes, that you would like your grade report for this submission sent to. Only list one e-mail address. 

FILENAME: This is the name of the file, including extension, surrounded by double quotes with no additional spaces inside the quotes. The extension should be all lower case - all other characters should be upper case.


Documentation of Waivers

Synopsis

Deviations from the standards must be documented to avoid penalties.

Detail

If you need to (notice the distinction between "need" and "want") to deviate from the Style Guidelines you must indicate this in the Source Code file. The most common waiver you will need to document are compiler warnings that you are unable to suppress.

For each item being waived, you need to clearly indicate what is being waived and why it is being waived. In the case of compiler warnings, this should include an explanation of why it is believed that the warning is not an issue.


Program Exit Values

Synopsis

Your program WILL return an integer value. A normal exit will use a return value of zero while non-normal exits will return a nonzero value whose meaning is documented in the source code.

Detail

Since your main() is declared as an integer function, you are expected to return an integer value. While you will not be using these values, the values are returned to the operating system and could, in concept, be accessed and used by a program calling your program. This might be used, for instance, by an automatic grading program that runs your program and feeds it good data on one pass and bad data on another pass looking for the exit code issued by your program to signal that the bad data was trapped.

In this course, you are expected to use an exit value of '0' if your program runs and exits normally. You are expected to use non-zero exit values if your code is exiting in an abnormal fashion and you are expected to document at the top of your code what those values mean. For instance, if you are opening two different data files, a return code of 1 might indicate that the first file failed to open and a return code of 2 might indicate that the second code failed to open. A return code of 3 might indicate that the data file contained data values that you couldn't work with.

To exit you program from any function other than main, you can either pass a return value that indicates an error to the calling function and walk the error code back up to main(). This is the approach that a structured programming purist would advocate. But the C language includes a function that is specifically intended to provide a shortcut for this situation - the exit() function found in the file stdlib.h. This function exits your program and returns the value passed to it from any point within your program structure.

Your exit values should be done via symbolic constants that are documented in your source code file. The recommended names for these constants should be "EXIT_" followed by a short descriptor of what the condition is such as "EXIT_FAIL_FileDidNotOpen".


Pseudocode Synopsis

Synopsis

The top few levels of your pseudocode should be included with your source code.

Detail

In order to provide the grader with a "big picture" idea of your approach to the problem, include the top few levels of your pseudocode in your source code file. A reasonable rule of thumb is that this should be approximately one screen of text - roughly twenty to thirty lines.

This synopsis should reflect the code as it is submitted as opposed to the pseudocode that was submitted previously. If there is any difference, that difference must be included in the Pseudocode Deviations section.


Pseudocode Deviations

Synopsis

Deviations from the originally submitted pseudocode must be documented.

Detail

The purpose of preparing and submitting pseudocode prior to implementing the source code is to encourage the practice of focusing on the program logic prior to dealing with program syntax. To this end, it is expected that your submitted pseudocode be sufficiently thought out that there should be few, if any, deviations from it in the final source code. If there are, it is an indication that insufficient effort was put into algorithm development. To encourage the correction of this situation, any disagreement between your submitted pseudocode and your submitted source code must be documented including a description of why the deviation is needed and/or desired.


File Inclusions (#include)

Synopsis

Include the names of all elements used from the included file.

Detail

Including a file for evaluation by the preprocessor should reflect a need for something contained in the file being processed and not a general laziness on your part that favors blasting the compiler with every header file you have ever used instead of learning which header files give you access to which functions. 

To both document why a particular header file is being used and to assist you in learning which header files are associated with which functions, you are expected to place the names of functions and/or constants actually used in your code next to the #include directive.

If the element is a function or parameterized macro, this should be indicated by playing a pair or parentheses after the name.

For example:

For instance:

Defeats the purpose and is not acceptable.


Unparameterized Macros (#define) 

Synopsis

Symbolic Constants should be uppercase and surrounded by parentheses if appropriate.

Detail

Unparameterized Macros, also known as "symbolic constants" or "pound defines", should be used liberally. Many hardcore programmers contend that hard coded numbers should never appear in the body of the code. This is because it is frequently these numbers that get changed as code evolves and the ability to change all of the related values throughout the code by simply changing a few #define statement is a compelling argument. We will be no where near this demanding in our standards, but any place where a user defined quantity which is constant throughout the code but which might change from one compilation to the next is an example of where a #define is appropriate and where the grader will look more favorably upon your work if you use one.

Similarly, constants that have some intrinsic interpretation, such as the the value of pi or the value of a logical false, should be defined as symbolic constants. This tends to make the code much more readable and maintainable.

All #define constants should be all, or at least mostly, upper case.

To associate a value with a name through the use of a #define statement, you should always enclose the value in parentheses. The reasons for this will be explained in detail when you learn about writing parameterized macros.

To associate a string constant (i.e., a string of text) with a name through the use of a #define statement, you should enclose the string in double quotation marks.


Parameterized Macros (#define)

Synopsis

Enclose all arguments in a parameterized macro in parentheses and enclose the macro body as a whole within parenthesis.

Detail

Arguments of parameterized macros should be surrounded by parentheses wherever they are used within the macro and the macro body as a whole should surrounded by parentheses. This is to ensure that expressions used as macro arguments are fully evaluated prior to interacting with the contents of the macro itself and that the macro is fully evaluated before the result is used in the expression containing the macro call.

Parameterized macros are often used just like a function - in fact many functions from the standard libraries are actually implemented as macros. Therefore the names of parameterized macros generally follow the same convention that would be used if it were implemented as a function.


Global Variables

Synopsis

Do not use global variables.

Detail

Repeat three times while standing on one foot - "global variables are bad." 

While seemingly convenient, they shatter the very principles that C was founded on - namely modularity and least privilege. Your code should not have any global variables. Global variables have their place in the field of programming, but most programs which you will write do not need them and they invite many problems. If you feel that a global variable is most appropriate (notice the use of the word 'appropriate' as opposed to the word 'convenient') for a particular use in one of your programs, you had best make a good case for that decision in the program documentation and do not be surprised when you still lose points because the grader disagreed with your reasoning. Hint: Do not use globals - at least in your final code.

One very valid use for globals is in debugging your code. They provides a fast and efficient means of getting information into and out of functions without having to make modifications to your function declarations and function calls. But notice that this represents a specific, focused, and very short term use of globals. Be sure to remove any such global variables prior to submitting your code for grading.


Variable Declarations

Synopsis

ALL local variables will be declared at the top of the function in which they are defined prior to any executable code.

Detail

Variables will be declared at the top of the function in which they are used and prior to any executable code. C compilers permit variables to be declared at the beginning of any block of code - and hence making them local to that block - and while good reasons do exist for exploiting this ability, none of the code that you will be writing justifies the reduction in reliability that such declarations often create - especially for new programmers.

Some compilers permit variables to be declared anywhere prior to their first use. This is a non-compliant language extension. If you submit such code and it does not compile on the grader's machine, it will be treated like any other non-compilable code. 

Special Note: It has been observed that the "official" compilers for this course will occasionally compile the type of non-complying code described above. The reason for this is not known and generally appears late in the semester. It is suspected that someone else has modified the compiler defaults. If you should find and use such a machine, the fact that your code compiled and ran on it will not be a defense against the consequences of violating this Style Rule since the whole purpose of this rule is to enhance code portability and your violation of it, irregardless of what the computer you were sitting at accepted - resulted in your code not being compilable on the grader's machine.


Variable Names

Synopsis

Variable names should be meaningful, mostly lower case, and follow the single character type conventions.

Detail

Use meaningful variable names. There are certain conventions that have arisen concerning the naming conventions for generic variables. These are summarized below and you are expected to observe them. All variable names should be all, or mostly, lower case. The use of title case (capitalizing the first letter of each word) is a good means to make long variable names readable particularly if you do not wish to separate words with an underscore.

Letters at the beginning of the alphabet (particularly a,b,c,d) should be used for parameters, possibly integer but more commonly floating point.

Letters in the middle of the alphabet (particularly i,j,k,l,m,n) should be used for integer variables.

Letters at the end of the alphabet (particularly r,s,t,u,v,w,x,y,z) should be used for floating point variables.

The above conventions arise out of the common usage of these letters in mathematics and greatly lend to the readability of your code. Likewise, ignoring them invites misinterpretation of your code. This is not to say that reasonable deviations cannot be made. If, in your program, time is an integer value then it is perfectly reasonable to use t as the variable for this and to make it an integer. The same would be true if you are working in a 3-D space with integer values - the use of x, y and z as integers is perfectly reasonable in this case.

Keep in mind that these guidelines are intended for short variable names - generally single letter names or names derived from single letter names such as i_max, or y_squared, or dx - that have no meaning in and of themselves.


Variable Initializations

Synopsis

Unless necessary (such as with static variables), variables will NOT be initialized at the time they are declared. They will be initialized at the most appropriate in the code.

Detail

Variables must be initialized to an appropriate value before they are first used on the right hand side of an expression - and nearly all compilers will generate a warning if it detects that this hasn't happened.

One way to do this is to explicitly initialize all variables at the time they are declared, although this practice is not recommended as it represents a general laziness in the coding approach and does increase the program's size and startup overhead by a marginal amount. Furthermore, it discourages developing a sense of when variable initialization is necessary and when it isn't and this is a valuable skill to possess both for code development and most especially for code debugging.

The best place to initialize a variable that has not otherwise been set to a value as part of the program's execution up to that point is shortly before its first use. This links the act of initialization with the logic that required it to be initialized in the first place which makes the code easier to comprehend, makes determining if the variable was initialized easy to determine while viewing the relevant code, makes it easier to evaluate if the value the variable was initialized to was reasonable, makes it easy to change the initialization value later (since the need to do this will usually be made while looking at the code that uses the variable the first time), and to make it more obvious that the initialization is redundant in the event that the logic is changed so as to make the initialization unnecessary.


Restrictions on use of break, continue, and goto statements

Synopsis

The use of break is restricted to a switch() statement and the use of continue and goto is prohibited.

Detail

These statements are a means of performing unconditional jumps and violate the concept of Structured Programming. The only exception to this is the use of a break statement within a switch() statement - in fact the use of a break statement at the end of each case block is the only way to make a switch() statement follow the Structured Programming model internally.


Void Function Types

Synopsis

All void functions will be declared as such.

Detail

The current C Standard, C99, requires functions that do not return values to be explicitly declared as type void.


Void Parameter Lists

Synopsis

All functions, including main(), that take no arguments must have a void parameter list

Detail

If a function does not take any arguments when called will have a parameter list consisting of the keyword "void". No parameter list will be left empty.


Function return Statements

Synopsis

Function return statement expressions will NOT be surrounded by parentheses.

Detail

To emphasize that the return statement is not a function, return statements will not not have an outer pair of parentheses surrounding the return value or expression.


Function Order

Synopsis

Functions will be ordered in reverse hierarchical order with main() last.

Detail

Your main() should be the LAST function in your program file. Nothing else should appear after it. This serves two purposes - first, it allows functions to be written in an order such that, unless they are recursively related, no function prototypes are needed. As a result, functions that are inadvertently related in a recursive fashion will cause linking errors and can therefore be identified.

Functions that are used directly by main() should be declared as a group directly above main(). Functions that are only called by those second-tier functions should appear next and so on.


Function Length

Synopsis

Functions should be displayable on one screen of text.

Detail

A good rule of thumb is that if a function can't be displayed on a single screen of text then the function should probably is too complex and should be broken down into more modular blocks. In addition to helping control modularity, maintainability is significantly enhanced by being able to see all of a function's code on the screen at the same time.

The two common exceptions to this rule involve large switch() constructs and large blocks that primarily print out information. When this is the case, effort should be made to place these constructs in a function that does little, if anything, beyond supporting the construct.


Function Prototypes

Synopsis

All function prototypes will include parameter names.

Detail

Although the compiler does not require parameter names in function prototypes and ignores any that are supplied, the are frequently quite useful as a quick reference to what information is associated with each argument to be passed. Furthermore, creating a function prototype from a function header is a simple matter of copying the header and appending a semi-colon.

Therefore, your function prototypes are expected to include parameter names and these should match the ones in the function header. As with all variable names, some effort should be made to make them meaningful.


Function Prototype Reference List

Synopsis

A set of prototypes for all functions defined in the file should appear above main().

Detail

A set of function prototypes for all functions - except main() - should appear immediately above main() to serve as a quick reference to those functions. These function prototypes should be in the same order as the function definitions.

No function prototypes should appear anywhere else in the code unless they are actually needed - and they should only be needed for recursively-related functions.


Function Declaration for main()

Synopsis

The only acceptable function headers for main() are

int main(void)    or    int main(int argc, char *argv[])

Detail

Unless accepting command line arguments, the expected form of main() function header is:

int main(void)

If you are accepting command line arguments, then the header it so be:

int main(int argc, char *argv[])

A common convention in the past was to simply use

main()

and let the compiler interpret it according to it's default. However, this is a classic example of letting the compiler make your decisions for you and code written this way was frequently not portable to a different compiler because the new compiler's default was different. Furthermore, most "hosted environments" (which your programs are) require a return value and failing to provide one can cause serious run-time problems. As a result, the first declaration shown above is now by far the preferred version and is explicitly required by the most recent ANSI/ISO C Standard (C99).

You will notice, however, that the authors of your text use the shortcut convention - but keep in mind that your text was published prior to the adoption of the C99 standard.


Integer vs. Floating Point Constants

Synopsis

Represent integer constants as integer values and floating point constants as floating point values.

Detail

Literal constants should be expressed in their "native form" meaning that if the quantity represents something that is fundamentally an integer value (such as the number of increments a range is divided into) then it should be expressed as an integer whereas if the quantity is fundamentally a floating point quantity, even if the particular value happens to also be an integer, then it should be expressed as a floating point value. Generally this means explicitly tacking on a decimal point and tenths digit - e.g., writing 12 as 12.0.


Integer vs. Floating Point Division

Synopsis

Type cast division operands to yield integer/integer or floating/floating as appropriate.

Detail

Operations that are intended to be floating point operations should have floating point operands. This is particularly true of division operations where both the numerator and the denominator should be type cast if necessary. It is true that the compiler will force floating point division as long as one or the other is a floating point value, but by getting in the habit of explicitly ensuring that ALL division operations are either integer/integer or floating/floating, you are highly unlikely to let a mistake slip by or to introduce one during a subsequent edit. After a while, this will become very natural and it only has to prevent one or two such errors from slipping through during the course to more than pay for itself.


Equality Comparisons

Synopsis

Place constants expressions, if available, on the left side of an equality comparison.

Detail

A common error (a very common error) is to accidentally use the assignment operator (=) where you meant to use the equality operator (= =). In many languages, the contexts in which these two operators can be used are mutually exclusive and therefore both operators use the same symbol. The intrinsic flexibility of C permits many situations in which it is legal to use either and therefore each is represented by a different symbol. Mixing them up is a common enough error that most compilers are able to catch the accidental use of the assignment operator where equality was intended, at least in certain circumstances and issue a warning. Ignore such warnings at your own peril.

The guideline for this course is a trick that can and will save you many, many frustrating hours of debugging time. Get in the habit of writing equality comparisons that involve a constant or an expression such that the constant or expression is on the left hand side of the operator. Hence, write (0 = = a) instead of (a = = 0). If you forget the second equals sign, the first becomes a syntax error while the second is perfectly legitimate C code which would, at best, produce a warning. It is virtually guaranteed that you will make this mistake many times during this course - and many more for as long as you are writing C programs. Be forewarned, if you spend a few hours, or days, trying to figure out why your program always crashes because you didn't follow this guideline, your tears will fall on highly unsympathetic shoulders.


Floating Point Equality

Synopsis

Never check for exact equality involving floating point expressions.

Detail

Checking for exact equality (or inequality) on floating point quantities is almost always a bad idea. The proper way to test for equality is to check to see if the two values are sufficiently close together so as to be effectively equal for the purpose of the test. How this is done depends on the situation, but it is usually sufficient to see if the absolute value of the difference between the two values is smaller than some threshold value. It is generally accepted that this threshold value should be represented by a #define constant (typically called EPS or EPSILON).


Verification of File Open Operations

Synopsis

All file open operations will be verified prior to any other operation on that file.

Detail

A very common mistake is to open a file and proceed to interact with it even though the file failed to open. This can have disastrous consequences. Therefore, any time a file is opened the success of that operation will be verified by checking for a non-NULL return value from the fopen() call. If a NULL pointer is returned, some appropriate action will be taken even if it is only issuing a warning message and exiting the program.