Code /

C Style

Reading

Cycling

X-Wing

Infinity

Warhammer 40k

Hobby

Nook

sidebar

C Style

C Style

This page documents my personal C programming style and design guidelines. Some of it is fairly idiosyncratic and solely presentation oriented. Other aspects are actually good design tactics to employ.

Obviously these are just guidelines, and should be broken where it makes sense. A rule of thumb I like is that you should always program smart, not always "correctly."

Top Level Naming Conventions

The following are rules for constructing and navigating primary, publicly exposed identifiers:

  1. Names are hierarchical, beginning with a project namespace and delimited by underscores.
  2. Namespace and object components are fully lowercased.
  3. Function and method components with compound names are lower camel cased.

Examples

Some examples from the tj-tools library:

  • tj_buffer
  • tj_buffer_create()
  • tj_buffer_getBytesAtIndex()
    • The method component (getBytesAtIndex()) is lower camel cased.
  • tj_searchpathlist
  • tj_searchpathlist_locate()
    • The object component (searchpathlist) is fully lowercased.
  • tj_solibrary
  • tj_solibrary_entry
    • A sub-object (entry), which doesn't sense as a standalone entity and has either a direct or conceptual association to a parent object, is nested under the parent (tj_solibrary).
  • tj_solibrary_entry_getSymbol()

Objects and Interfaces

Object classes are captured as structs with conceptually associated functions as methods:

  • Objects are named hierarchically, as above.
  • Method functions are named as above, nested under the object hierarchy.
  • The first parameter of a method function is the object of which it is treated as a component.
  • Objects are created using a constructor function named as the object name suffixed by '_create'. This may have parameters.
  • Objects are destroyed by a destructor function named as the object name suffixed by '_finalize', taking the object itself as the sole parameter.

In general, only the struct name and the method functions should be exposed. This ensures proper encapsulation of the object, preventing user code from directly manipulating the internals. Code is structured as follows:

  • The object interface is defined in a header file named as the object name suffixed by '.h', which declares the struct name as a typedef, and the signatures of the public methods.
  • Implementation is kept in a code file named as the object name suffixed by '.c'.
  • If some internal details need to be selectively exposed, that friend interface should be exposed in a header file named as the object name suffixed by '_impl.h'. This applies mostly to abstract classes and plugin or aggregate containers.

"Small" sub-objects may be defined and implemented in the header and code file of their parent objects.

Interfaces and abstract classes are captured as exposed structs with function pointers that are constructed and filled in by implementing objects.

Within object structs, several style rules are adhered to:

  • Member variables begin with an 'm_' and are lower camel cased.
  • Interface methods (function pointers) do not have the 'm_' prefix but are lower camel cased.

Unlike 'proper' object oriented environments such as C++, member variables can't be accessed directly in C. They're always referenced via an accessor, either '.' or '->', which renders the 'm_' prefix somewhat superfluous compared to those languages. However, it is maintained in order to differentiate from function pointer methods in much the same manner.

Examples

(* tj_log_outchannel has a good example of interfaces *)

Header Files

License

Header Guards

Recent Changes (All) | Edit SideBar Page last modified on October 20, 2012, at 04:50 AM Edit Page | Page History
Powered by PmWiki