C's #pragma exists so we can pass various nonstandard information to the C compiler. As alluded to above, it isn't necessarily well-liked by compilerers. Why not? After all, there are lots of good reasons to want to communicate some nonstandard information to your C compiler. If this information is not necessary to compile the program, but only to reduce warnings or produce better code, why not use #pragma?

On its own, #pragma isn't standard enough to be useful

Of course. It's meant for nonstandard features. Only most "nonstandard" features will still be supported by almost all compilers. And each will do it differently.

Let's look at a typical example. Many C compilers support inlining of functions (at least within the same source filecompilation unit). Some heuristics are used to determine inlinability, but you might want to override them. Surely we can use #pragma to do it!

Well, almost.

  • SGI's C compiler lets you say #pragma inline global function (as well as some more complex options to fine-tune the inlining) to inline function wherever it appears. If you say just #pragma inline function then inlining occurs only within that scope.
  • Sun's Forte C compiler lets you say #pragma inline function. It has fewer options than SGI's #pragma inline (SGI is more of a supercomputing company than Sun). In fairness, judicious placement of #pragma inline can yield the same intended effect in both compilers, as long as you just want expansion throughout the file. The #pragma must appear after the function has already been declared.
  • Compaq's C compiler requires brackets around the function names. Luckily, the brackets do no harm in the other 2 compilers.
By sheer luck, the form #pragma inline (function), placed after the function has already been declared, works on all 3 compilers. Except if it's not in the top-most scope, in which case it will have different semantics on SGI. And if our function is recursive, we'll have to predeclare it then #pragma inline it to get one level of recursion inlined on all our platforms.

Dealing with compiler dependencies

The way to deal with compiler dependencies like this (and they are unavoidable) is to use #ifdef to determine which compiler we're using. So we could say

/* Define function, then ... */
#ifdef __sgi
#pragma inline global function
#elif defined(__alpha)
#pragma inline (function)
#elif defined(__sun)
#pragma inline function
#endif
which has a fighting chance of being understood by an experienced user of the compiler on her native platform.

Abstracting #ifdefs away

The code above is a maintenance nightmare. If we want to add support for the new ariel Si Si compiler, we have to add a #elif clause on every inlining. The solution to this is abstraction: create some higher level construct INLINE(function) and use that instead. The definition of the construct will use #ifdefs, but they'll all be in one spot, and easy to maintain and modify.

Presumably, INLINE will be a macro, and we'll #define it appropriately.

Excuse me, did someone say "macro"? Because you cannot standardly use macros and preprocess constructs. And anything beginning with # belongs to the preprocessor.

So there is no maintainable way to use #pragmas in your code.

Epilogue

  1. You C++ weenies in the corner can stop snickering RIGHT NOW! The inlining example was just that. C++ has #pragmas just like C has them, and they are no better for when you need them.
  2. The alternative? Do like the gcc (GNU) people do, and ignore that part of the ISO C standard (it is standard-conforming to do whatever takes your fancy with #pragma). Instead, introduce new reserved keywords such as __inline__ (anything which begins with two underscores is part of the implementation namespace, so this too is standard-conforming). This can be used portably:
    #ifdef __gcc
    #define INLINE(f) __inline__(f)
    #else
    #define INLINE(f)
    #endif