testing compile time constness and null pointers with C11’s _Generic

Sometimes in C it is useful to distinguish if an expression is an “integral constant expression” or a “null pointer constant”. E.g for an object that is allocated statically, only such expressions are valid initializers. Usually we are able to determine that directly when writing an initializer, but if we want to initialize a more complicated struct with a function like initializer macro, with earlier versions of C we have the choice:

  • Use a compiler extension such as gcc’s __builtin_constant_p
  • We’d have to write two different versions of such a macro, one for static allocation and one for automatic.

In the following I will explain how to achieve such a goal with C11’s _Generic feature. I am not aware of a C++ feature that provides the same possibilities. Also, this uses the ternary operator (notably different in C and C++), so readers that merely come from that community should read the following with precaution.

Continue reading “testing compile time constness and null pointers with C11’s _Generic”

Advertisements

surprising occurrence of identifiers in header files

I remember being stuck sometime ago because a system header at the time on the platform that I was using defined the undocumented identifier barrier. IIRC this even was a macro, which made the bug really hard to track, seemingly harmless code simply exploded.

Hopefully nowadays platform implementors are a bit more careful in not polluting the namespace, but still avoiding naming conflicts is not so easy. E.g inline functions are a useful tool when you want to expose small functions to all compilation units of a program. There is one pitfall, though, when it comes to naming conventions for their parameter names and local variables. If you get the name wrong, as in this simple example

inline double my_sin(double PHI) { return sinf(PHI); } 

other users of your code might encounter random problems if they define a macro PHI.
Continue reading “surprising occurrence of identifiers in header files”

Emulating C11 compiler features with gcc: _Atomic

The new support for atomic operations in C11 is probably the most useful one. Support for atomic instructions is present in all commodity processors since at least 20 years, but a standardized interface in one of the main programming languages was really missing. Up to now you always had to implement stubs for these operations in assembler. This by itself was not as difficult for a given platform, but writing platform independent code quickly became tedious.

P99 now has an emulation of parts of these features that allow you to use them in a preview for C11. This implementation mainly uses (again) extensions of the gcc family. It should even work for older versions of gcc that don’t implement their __sync_.. built-in.

Continue reading “Emulating C11 compiler features with gcc: _Atomic”

Handling control flow inside macros

When people program macros that they want to be executed anywhere where a statement could be, they often use the

do {...} while(0)

construct. This construct has a big disadvantage in that it may change control flow in an unexpected way when you’d use it as a generic macro tool to collect statements:
Continue reading “Handling control flow inside macros”

P99 is released

P99 – Preprocessor macros and functions for C99

P99 is a toolbox of macro and function definitions that ease the programming in modern C, aka C99. By using new tools from C99 it implements default arguments for functions, scope bound resource management, transparent allocation and initialization, …

The complexity of the tools ranges from very simple (but convenient) macros such as P99_INIT to relatively complex ones such as P99_UNWIND_PROTECT.

P99 is not a library but just a set of include files. You may include the whole by just using “p99.h” or cherry pick individual parts to your needs. You will not have to link against a special library the “only” prerequisite is that your compiler supports modern C, aka C99, to a wide extent.

So far I have tested P99

  • on linux systems
  • with INTEL 32 / 64 bit and ARM processors
  • with four different compilers: gcc, clang, opencc and icc
  • with code from an internal project.

If you are developing for another setting I would be very much curious to hear of your experience with P99.

P99 can be downloaded at p99.gforge.inria.fr. It is licensed under the QPL.

Macros versus inline functions

Functions (whether inline or not) and macros fulfill different purposes. Their difference should not be seen as ideological as some seem to take it, and what is even more important, they may work nicely together.

Macros are text replacement that is done at compile time and they can do things like

#define P99_ISSIGNED(T) ((T)-1 < (T)0)

which gives you a compile time expression of whether or not an integral type is signed or not. That is, they are ideally used when the type of an expression is not known (at the definition) and you want to do something about it. On the other hand, the pitfall with macros is that their arguments may be evaluated several times, which is bad because of side effects.

Functions on the other hand are typed, which makes them more strict or, phrased negatively, less flexible. Consider the functions

inline
uintmax_t absU(uintmax_t a) {
  return a;
}
inline
uintmax_t absS(uintmax_t a) {
   return (-a < a) ? -a : a;
}

The first implements the trivial abs function for an unsigned integral type. The second implements it for a signed type. (Yes, it takes an unsigned as argument, this is for purpose.)

We may use these with any integral type. But, the return type will always be of the largest width and there is a certain difficulty on knowing how do choose between the two.

Now with the following macro

#define ABS(T, A) ((T)(P99_ISSIGNED(T) ? absS : absU)(A))

we have implemented a

  • family of functions
  • that works for any integral type
  • that evaluates its argument only once
  • for which any recent and decent compiler will create optimal code

Well, I admit that doing this with abs is a bit artificial, but I hope you get the picture.