Project Home
Project Home
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
wiki1041: GeneralDeveloperInformation (Version 3)

QNX has been developing software for a number of years, and coding techniques and styles have evolved over that period of time as technology has evolved ... and so we evolve with it.

The QNX Coding Standard and the QNX Best Practices documents capture some of the lessons learned during the development of our software for multiple target architectures and multiple host environments. The documents are also continuously evolving as we gain new experience and introduce additional technologies.


QNX Coding Standard#


1. Introduction

CONSISTENCY is at the heart of readable source code. Mixed coding style is harder to maintain than any particular "bad" coding style. When working on existing source code (GNU, Dinkum, QNX4, Photon etc), the particular format and style used by that source and its associated modules (headers, other source files) should be maintained regardless of this document. The intention is not to retro fit a new style onto all of QNX's existing source code base.

For new projects this document provides a common set of C coding standards and recommendations that should be followed. Standardizing will provide consistancy, improve portability, reduce errors and help new employees/third parties and customers reading our source learn the "QNX way".

2. What To Do When It Isn't Specified

This document provides a number of guidelines based on existing QNX source code and industry best practices; it does not cover every single case imaginable. When something is not specified (ie continuation behaviour of long function names or long argument lists) and there are no examples in the existing source to follow (Rule #1 Be Consistant) make a choice based on providing a readable result that you will be able to use consistantly.

3. File Organization

There is no maximum length limit for files, but files with more than about 1000 lines are cumbersome to deal with. Lines longer than 79 columns are not handled well by all terminals and should be avoided if possible. The maximum line length is 132 columns.

3.1. Source File Naming Conventions

Source file names are made up of a base name, a period and a suffix. File names must be lower-case, do not have spaces, contain only a single 'dot' and have meaningful names. Avoid using file or directory names that can cause problems for certain filesystems: CON, PRN, AUX, CLOCK$, NUL, COM1-COM9, LPT1-LPT9 should be avoided.

When working with QNX DDK's the file names/directory organization should be adhered to.

Some compilers and tools require certain suffix conventions for names of files. The following suffixes are required:

  • C header file names must end in .h
  • C source file names must end in .c
  • C++ source file names must end in .cpp
  • C++ header file names must end in .hpp
  • Java source file names must end with .java
  • Assembler source file names must end in .S or .s
  • Yacc source file names end in .y
  • Lex source file names end in .l
  • ... add other types here...
3.2. Source Files

The order of sections for a program file are as follows:

QNX License/Copyright Header (refer to section 7) Module Description (refer to section 4.8)

#include Directives typedefs externs

globals Source code ....

3.2.1. Order of Functions Within a File

Deliberately arrange the order in which the functions are defined in a file so as to make forward declarations unnecessary and your source easier to maintain and follow. Typically, you do this by placing the function that calls most other static functions at the bottom of the source file and placing the functions at the bottom of the caller/called hierarchy towards the top of the file.

3.3. Header Files

Header files should keep the number of other headers they include to the bare minimum, subject to other rules - see below.

3.3.1. System Headers (i.e. headers files in /usr/include):

The order of sections for are as follows:

	QNX License/Copyright Header (refer to section 7)

	Module Description (refer to section 4.8)

	#ifndef _HEADERFILE_H_INCLUDED
	#define _HEADERFILE_H_INCLUDED

	... stuff in file ...
  
	#endif
For header files in sub directories use the following syntax:
	#ifndef _DIR_HEADERFILE_H_INCLUDED
	#include <DIR/HEADERFILE.h>
	#endif
where:
	DIR = directory relative to /usr/include where the file will exist
	HEADERFILE = name of the file
The special case of files in /usr/include/sys will have DIR = "" resulting in names such as HEADERFILE.

For the special case of header files in /usr/include/sys

	#ifndef __HEADERFILE_H_INCLUDED
	#include <sys/HEADERFILE.h>
	#endif
For all type references in public header files other than those that are fundamental types, the file must include the appropriate definitions for those types. (If these definitions are in some other header files, thosefiles must be included enclosed by the appropriate #ifndef ... #endif blocks.)

Whenever possible, public header files must avoid polluting the user name space with extra symbol names. This means that when using types, if there's a version of the typename in the implementer's reserved name space (leading underscore's), you should use that version rather than the public typename. All of the reserved name versions are defined by including <sys/platform.h>, so by including that file, you hopefully will be able to avoid including other headers and introducing more symbol names than necessary. E.g. do:

	#include <sys/platform.h>
    
	typedef _Uint32t  my_type;
 
rather than:
	#include <inttypes.h>

	typedef uint32_t my_type;
In headers, function prototypes parameter names should all be declared so that they are prefixed by . This is just a safeguard against unexpected macro expansions for common names in parameters.

When defining constants to be used in flags, make sure the constants clearly indicate how large the target flag variable is. i.e. if the target flag storage is 32 bits, add appropriately enough leading zeroes to the constant.

Surround any typedef's or function prototype definitions in a public header file using:

	__BEGIN_DECLS

	/* typedefs and function prototypes go here */

	__END_DECLS
The BEGIN_DECLS & END_DECLS macros are obtained by including <sys/platform.h>.

New header files should as often as possible avoid installing to /usr/include to avoid pollution of the /usr/include directory with a lot of random stuff. Preferably, if the header files belong to a specific module, then the header could install to /usr/include/modulename (as a directory, with the actual headers under it).

Existing module subdirectories:

	ppc, mips, x86, arm, sh
		CPU specific headers
	hw 
		headers describing hardware stuff
	photon 
		Photon headers
3.3.2. Application Header Files: The order of sections are as follows:
	QNX License/Copyright Header (refer to section 7)

	Module Description (refer to section 4.8)

	#ifndef HEADERFILE_H_INCLUDED
	#define HEADERFILE_H_INCLUDED

	... stuff in file ...

	#endif
Application header files should never use types defined in platform.h. They should instead use inttypes.h. E.g. do:
	#include <inttypes.h>
    
	typedef uint32_t my_type;
rather than:
	#include <sys/platform.h>
    
	typedef _Uint32t  my_type;
3.4. Executable/Library File Naming Conventions

Refer to requirements/design documents.

3.5. Installation

Refer to Filesystem Hierarchy Standard (version 2.2 final)

3.6. Source Code Build & Layout

Refer to Source Code Build & Layout document.

4. Specific Code Formatting Issues

The following points address specific code formatting issues. CONSISTANCY with existing source formatting and style takes precedance over these guidelines.

Running a formatting utility like indent over source code should be considered only as a last resort to restore sanity to source code that has been irreparably infected with multiple formats and styles. In this case it is suggested to use these guidelines for the re-formatting.

4.1 Indention

The standard indention is four (4) spaces.

4.2. If...Else Statements

The else clause of an if {...} else {...} should be "cuddled" as shown in this example:

	if (something) {
		/* Do some stuff here. */
	} else {
		/* Do something else. */
	}
4.3. Case Statements

Case statements should be "cuddled" as shown in this example:

	switch (number) {
	case 0:
		...
		break;
	case 1:
		...
		/* Fall through */
	default:
		break;
	}
Continuations from one case to another should be clearly identified with a comment as above.

4.4. For Statements

For statements should be "cuddled" as shown in this example:

	for (cnt = 0; cnt < some_value; cnt++) {
		... do stuff ...	
	}
4.5. While Statements

While statements should be "cuddled" as shown in this example:

	while (some_condition) {
		... do stuff ...
	}

	do {
		... do stuff ...
	} while (some_condition);
4.6. Format of Data Structures

Do not make assumptions about the layout or padding of a structure or the allocated size of a data structure. These depend on the compiler implementation and can vary significantly with the type of target CPU.

When defining a structure that will be used in message passing or will be written to external device (e.g a hard disk, serial line), the types of all the fields must be explicitly sized. eg: struct foo { int bar; }; is a no-no, while for a PUBLIC header (ie /usr/include)

	struct foo {
		_Int32t bar;
	};
or NON-PUBLIC header
	struct foo {
		int32_t bar;
	}; 
is correct. Note that even when a _Int32t style declaration is used the documentation should use the int32_t as the reference type.

On the opposite side, do NOT use an explicitly sized type unless you really need it - internal structure definitions can get along quite happily without them and you don't limit yourself in the future when we're running on a 64-bit CPU (and that's going to be sooner than you think). It is also a good idea to plan for expansion when defining public data structures. ie

	struct foo {
		int     bar;
		int     rsvd[4];
	};
4.7. Data Alignment

Align your data, especially structure elements, on their native boundaries. This means that shorts should start on any even address, longwords on addresses evenly divisible by four, and 64-bit values (quadwords) on addresses evenly divisible by eight.

	struct foo {
		int16_t	type;
		int16_t	rsvd;	 /* Explicit padding/reserved */
		int32_t	data;
	};
4.8. Module Description

Each source/header file should contain a block comment immediately after the license header that gives a short description of what the module does and (if not clear) how to use it. Discussion of non-trivial design decisions and side-effects is also appropriate. For example:

	/*
	 * options.c
	 *
	 * This file contains code to parse command line options.
	 */
4.9. Function Description

Each function should be preceded by a block comment. The comment should provides usefull information about:

  • A synopsis of what the function does
  • Appropriate or in appropriate uses for the function
  • Side effects (state changes, acquired locks) of calling the function
  • Any non-trivial design decisions or historical rationale for behaviour

The comment block should be formatted in a manner such that it is easy to read and automated documentation generation tools such as doxygen can extract meaningful developer information. Avoid dup-licating information clear from the code. One doxygen example format:

	/** 
	 * function_name A short synopsis of the function
	 * - Description: This is a longer description of what
	 * the function does.
	 * - Arguments:
	 *   - param1: The first parameter description
	 *   - param2: The second parameter description
	 * - Returns: 
	 *   - Something that comes back
	 */         
Real world example:
	/**
	 * smc9000_parse_options: command line option processing
	 * - Description: This function handles the special exception
	 * cases in the general option processing for the SMC driver.	
	 * - Arguments:
	 *   - opt: a pointer to the command line options
	 * - Returns:
	 *   - Option parsing status: EOK on success, EINVAL on failure	
	 */         
	 int smc9000_parse_options( char *opt )
4.10. Function Naming

Public functions should be named using all lower case letters and underscores.

5. Comments

C style (/* */) and C++ style (//) comments are allowed. The only excecption is that C++ style comments are not permited in public header files.

Short/Single Line Comments

Very short comments may appear on the same line as the code they describe, and should be tabbed over to separate them from the statements. If more than one short comment appears in a block of code they should all be tabbed to the same tab setting.

	if (a == EXCEPTION) {
		b = TRUE; /* special case */
	} else {
		b = isprime(a); /* works only for odd a */
	}
Formatting Block Comments

Format block comments as follows:

	/*
	 * This is a block comment. Don't embellish these with lots of "stars
	 * and bars."
	 */
Some Comments about Comments

Comments must be in english and should tell the reader something non-obvious. A comment that repeats what is blindingly obvious is annoying at best. The following is an example:

	counter += 10;    /* Add ten to counter */
It is often better to aggregate comments about high-level and architectural issues in one place, to allow the reader and maintainers of your code to learn much more in a shorter time than if they had to piece together the issues and ideas about your features from comments strewn throughout several files.

6. Best Practices

The QNX coding best practices can be found in QMS0026.

7. License/Copyright Headers:

All source (*.c/cpp, *.h/cpp, *.s, *.S, etc) and common.mk's should have a license/copyright header at the top.

You don't have to have license/copyright headers for usage files or "Makefile"'s - if the Makefiles are using the common makefile scheme (that is, they just include "recurse.mk" or "common.mk").

All "old" copyright headers (e.g. OCL, QCL, CSL etc) are deprecated. The only copyright header that should be put on is the standard QSS_Copyright_Notice. The mechanism for annotating source code with this license is to make use of the QNX custom RCS tags that will be automatically updated on source code checkout/checkin:

$QNXLicenseC: $ : For use with C/C++ source files $QNXLicenseA: $ : For use with Assembly source files $QNXLicenseM: $ : For use with Makefile source files

For example:

	/*
 	 * $QNXLicenseC: $
 	 */
Assembly file:
	#
	# $QNXLicenseA: $
	#
If additional (file-specific) text is required, these can be inserted in the same comment block but after the second "$" character. For example:
	/*
	 * $QNXLicenseC: $
	 *
	 * This is some additional information that is being added
	 * as an extra part of this comment.
	 */