The flavor of C supported by GCC is often called GNU C. In the 1990s, GNU C filled in several gaps in the C language, providing features such as complex variables, zero-length arrays, inline functions, and named initializers. But after nearly a decade, C was finally upgraded, and with the standardization of ISO C99 and then ISO C11, GNU C extensions grew less relevant. Nonetheless, GNU C continues to provide useful features, and many Linux programmers still use a subset of GNU Coften just an extension or twoin their C99- or C11-compliant code.
One prominent example of a GCC-specific code base is the Linux kernel, which is written strictly in GNU C. Recently, however, Intel has invested engineering effort in allowing the Intel C Compiler (ICC) to understand the GNU C extensions used by the kernel. Consequently, many of these extensions are now growing less GCC-specific.
Inline Functions
The compiler copies the entire code of an inline function into the site where the function is called. Instead of storing the function externally and jumping to it whenever it is called, it runs the contents of the function directly. Such behavior saves the overhead of the function call and allows for potential optimizations at the call site because the compiler can optimize the caller and callee together. This latter point is particularly valid if the parameters to the function are constant at the call site. Naturally, however, copying a function into each and every chunk of code that invokes it can have a detrimental effect on code size. Therefore, functions should be inlined only if they are small and simple or are not called in many different places.
For many years, GCC has supported the inline
keyword, instructing the compiler to inline the given function. C99 formalized this keyword:
static
inline
int
foo
(
void
)
{
/* ... */
}
Technically, however, the keyword is merely a hinta suggestion to the compiler to consider inlining the given function. GCC further provides an extension for instructing the compiler to always inline the designated function:
static
inline
__attribute__
((
always_inline
))
int
foo
(
void
)
{
/* ... */
}
The most obvious candidate for an inline function is a preprocessor macro. An inline function in GCC will perform as well as a macro and receives type checking. For example, instead of this macro:
#define max(a,b) ({ a > b ? a : b; })
one might use the corresponding inline function:
static
inline
max
(
int
a
,
int
b
)
{
if
(
a
>
b
)
return
a
;
return
b
;
}
Programmers tend to overuse inline functions. Function call overhead on most modern architecturesx86 in particularis very, very low. Only the most worthy of functions should receive consideration!
Suppressing Inlining
In its most aggressive optimization mode, GCC automatically selects functions that appear suitable for inlining and inlines them. This is normally a good idea, but sometimes the programmer knows that a function will perform incorrectly if inlined. One example of this is when using __builtin_return_address
(discussed later in this appendix). To suppress inlining, use the noinline
keyword:
__attribute__
((
noinline
))
int
foo
(
void
)
{
/* ... */
}
Pure Functions
A pure function is one that has no side effects and whose return value reflects only the functions parameters or nonvolatile global variables. Any parameter or global variable access must be read-only. Loop optimization and subexpression elimination can be applied to such functions. Functions are marked as pure via the pure
keyword:
__attribute__
((
pure
))
int
foo
(
int
val
)
{
/* ... */
}
A common example is strlen()
. Given identical inputs, this functions return value is invariant across multiple invocations, and thus it can be pulled out of a loop and called just once. For example, consider the following code:
/* character by character, print each letter in 'p' in uppercase */
for
(
i
=
0
;
i
<
strlen
(
p
);
i
++
)
printf
(
"%c"
,
toupper
(
p
[
i
]));
If the compiler does not know that strlen()
is pure, it would need to invoke the function with each iteration of the loop.
Smart programmersas well as the compiler, if strlen()
were marked purewould write or generate code like this:
size_t
len
;
len
=
strlen
(
p
);
for
(
i
=
0
;
i
<
len
;
i
++
)
printf
(
"%c"
,
toupper
(
p
[
i
]));
Parenthetically, even smarter programmers (such as this books readers) would write:
while
(
*
p
)
printf
(
"%c"
,
toupper
(
*
p
++
));
It is illegal and indeed makes no sense for a pure function to return void
, as the return value is the sole point of such functions. An example of a nonpure function is random()
.
Constant Functions
A constant function is a stricter variant of a pure function. Such functions cannot access global variables and cannot take pointers as parameters. Thus, the constant functions return value reflects nothing but the passed-by-value parameters. Additional optimizations, on top of those possible with pure functions, are possible for such functions. Math functions, such as