P99
|
P99 uses some programming conventions that might be interesting for projects that include its header files.
Where we can, we try to conform to the C99 standard and to mark extensions clearly, if we use them.
The C specification has many places where it explicitly says that under certain circumstances the behavior of the resulting code is undefined. Generally this means that a conforming C implementation is not obliged to capture such circumstances and for code that uses such undefined behavior might do anything, from do-the-right-thing or crashing to eating your hard drive.
P99 should not produce any such undefined behavior.
In other places the standard leaves room for C implementations to specify certain behavior.
P99 tries not use any special feature that might be the result of such implementation specific behavior. This concerns in particular arithmetic on integer types. Here the standard allows certain variations:
sizeof
expressions for shifts.int
a
we would use -
(unsigned)a. This expression guarantees that the result is well defined even for corner cases (here a
being INT_MIN
in two's complement representation) and will never trigger a range error.typedefs
uintptr_t
or intptr_t
since they are optional in C. In particular we may not assume that there is any sensible conversion between pointers and integer types.Macro names that implement the functionality of P99 are generally uppercase. Exceptions from that rule are Macros that hide a function. All other identifiers are lowercase.
P99 uses the common prefixes P99_
and p99_
for macros and other identifiers, respectively. Future P99 versions could define new identifiers with these prefixes. If you include any of the P99 files, avoid using these prefixes for your own identifiers.
The same rule holds for the prefixes P00_and
p00_
which are used for auxilliary identifiers that need not be documented. Such identifiers are ignored in the doxygen documentation.
The P99 macros and functions as such should be independent of the execution system and compiler. Nevertheless, for the time being they are only tested on POSIX systems, namely Linux. So if problems are discovered with other systems, please let us know.
In contrast to that general policy, there is one file that is dependent on the system, p99_posix_default.h. As the name indicates it is designed for POSIX systems and provides default arguments for some POSIX functions.
Also, some of the examples throughout this documentation are taken from programs that would typically run on POSIX systems. We hope that such examples are obvious and don't need explanation for programmers of other systems.
Where possible, P99 uses initializers to initialize variables. For each type T
where such an initialization is possible, there should be a macro T_INITIALIZER
that does a standard initialization. Such a macro should use the Designated initializers scheme.
In case you want the default behavior of C, namely that all fields are recursively initialized with 0
then you could just use
to make this choice explicit.
Such initializers can easily be assembled together
As you can see in this example, INITIALIZER
can be a ‘normal’ macro or a function like macro.
For dynamic initialization we assume that an ‘init’ function exists that
Often when programming utilities for C that are supposed to return a pointer to an array or structure, the question of who is allocating the space arises: the caller or the callee.
P99 goes a different way, in that it tries to remove most of the burden from the programmer of both caller and callee. Let us look at the hypothetical function
which could be defined as being similar to the POSIX gethostname
function, only that it doesn't return an error indicator but a pointer to the name or a null pointer if it fails. An old time (and dangerous!) calling convention for such a function would perhaps have been to return a statically allocated buffer in case that the buffer
argument is a null pointer.
P99 lets you define more convenient and less dangerous calling conventions: Default arguments to functions allows us to define a macro of the same name that uses a compound litteral if no argument is given to the same function.
This defines three different macros. One that is used where the programmer places a call to hostname
. The other two, hostname_defarg_0
and hostname_defarg_1
, are used by the macro hostname
when the respective arguments are left out.
Now hostname
can be used in three different ways.
The later is then equivalent to
but without leaving a non-const access to the contents of tmp
.
It uses a temporary value that is only valid inside the block in which the get_hostname
macro is expanded. The handling of this temporary is implicit; neither the caller nor the callee have to worry of allocating or deallocating it. On the calling side this convention is simple to use without having the callee expose a static buffer.
In P99, it is currently applied in a few places, in particular in the header file "p99_posix_default.h". Its use will probably grow in future releases.