NASPRO - The 'NASPRO Architecture for Sound PROcessing'

User login

Who's online

There are currently 0 users and 0 guests online.

Syndicate

Syndicate content

Valid XHTML 1.0 Strict
Valid CSS
Viewable with Any Browser

C constructs

This chapter, unlike the previous ones, deals with functional and behavioural conventions; so, to better understand much of the discussion going on here, you should have some knowledge on how this library works. Please, refer to the other parts of this document.

Standard conformance

We've already said that this library is written in pure ISO/ANSI C, so don't ever use non standard stuff in the OS-independent part and, even in the OS-dependent part, avoid it as much as possible. Forget inline, bool, variadic macros, etc.

Functions

Needless to say that functions should be short, safe (in terms of concurrency as well as having all the assertions, messages, etc. needed), and do just one thing, when possible.

When declaring a function is fundamental to use the visibility macros (expect when defining static ones) provided by this same library (NACORE_PUBLIC_*(), NACORE_PRIVATE_*()) declared in include/NASPRO/core/cpp.h).

Never split a multiple variable declaration on more lines, since it is no improvement in readability at all (it's often the opposite). It's better to declare them separately in such cases.

In contrast to the GNU Coding Standards, having the else if condition on one line is perfectly fine (when used properly of course).

Assignments inside if conditions, instead, must be avoided (they're obviously OK in looping conditions).

When comparing a pointer to NULL, or when assigning NULL, please use NULL explicitly and not zero.

Do not use void casts.

Function prototypes must absolutely be declared with parameter names.

Macros

Macros should only be used when the operation is not worth a function (this may be a bit subjective, so it is good to see how things typically go in the rest of the source code), is always successful (can't generate errors) and when they don't actually hide important implementation details.

Always use brackets around the whole returned value and around parameters, when there are any.

Types

typedefs should only be used when declaring opaque types and machine-/system-specific wrapping types (for example to create equivalents of C99's int8_t, uint8_t, etc.). So there's no need to typedef structs and enums that can be directly accessed; this helps developers to immediately determine direct accessibility of data.

enum constants are to be preferred to #defined ones, since this allows the compiler to do type checking. #defines should be used only in case the values are likely to be used with more than one type (as in error codes). Please no const variables to store constant values, unless it's the only reasonable way.

Type inheritance

The concept of inheritance is usually associated with object-oriented programming languages (C++, Java, etc.), but it is possible to do something similar also in C quite easily. I first read about it in the "GNU Autoconf, Automake, and Libtool" book (also know as "The Autobook") by Gary V. Vaughan, Ben Elliston, Tom Tromey and Ian Lance Taylor.

While this is mostly a dirty trick, it can be tremendously useful in some cases. Using this is OK, but it has to be done very very carefully and with the brain turned on.

Copyright © 2007, 2008 Stefano D'Angelo