Inline functions and linkage

K

kid joe

Hi all,

Im very confused about how you should provide inline functions in a
library. Lets say the library is libjoe with headerfile <joe.h>. There
seem to be a few possibilities:

1) have the function defined in joe.h as static inline.

2) have the function defined in joe.h as inline and also include
an extern inline prototype for it in joe.h. (Make sure to use #pragma once
in joe.h)

3) have the function defined as inline in one of the *.c files
that make up libjoe, and put an extern inline prototype in joe.h.

Which of these is the best?

Also I guess it shouldnt be possible to call a private function from
libjoe (ie a static function in one of the *.c files that make up libjoe)
inside an inline function exported by libjoe, even though it would be
possible to call a static function in a non-inline function exported by
libjoe. How is that enforced? Is it by the compiler or the linker?

Cheers,
Joe
 
J

jameskuyper

kid said:
Hi all,

Im very confused about how you should provide inline functions in a
library. Lets say the library is libjoe with headerfile <joe.h>. There
seem to be a few possibilities:

1) have the function defined in joe.h as static inline.

2) have the function defined in joe.h as inline and also include
an extern inline prototype for it in joe.h. (Make sure to use #pragma once
in joe.h)

3) have the function defined as inline in one of the *.c files
that make up libjoe, and put an extern inline prototype in joe.h.

Which of these is the best?

Option 1 works, and it allows you to avoid the restrictions on inline
functions with external linkage: it can define a modifiable object
with static storage duration, and it can refer to identifiers with
internal linkage (6.7.4p2).

Option 2 is bad, since it provides only inline definitions of the
function. "It is unspecified whether a call to the
function uses the inline definition or the external
definition." (6.7.4p6) Therefore, you risk getting a link failure if
the compiler decides to call the non-existent external definition of
the function. Also, like most #pragma's, #pragma once is non-portable.

Option 3 is bad, because joe.h is unusable everywhere except the *.c
file that contains the actual definition of the function. "For a
function with external linkage, the following restrictions apply: If a
function is declared with an inline function specifier, then it shall
also be defined in the same translation unit." (6.7.4p6). This "shall"
does not occur in a "Constraints" section, so the behavior is
undefined if you violate it.

Option 4 would be to provide an inline file scope definition of the
function in joe.h, so it has implicitly external linkage, yet also
qualfies as an inline definition. Then, in the joe.c file, declare the
function with extern before #including joe.h, thereby making it an
external defintion. This gives the compiler the choice of either using
the inline definition from joe.h, or the external definition from
joe.c, whichever it thinks will produce the best results. As a general
rule the more freedom you give your compiler, the better the code that
it can generate. You should only restrict it's options if you don't
trust it to make the right choice.
Also I guess it shouldnt be possible to call a private function from
libjoe (ie a static function in one of the *.c files that make up libjoe)
inside an inline function exported by libjoe, even though it would be
possible to call a static function in a non-inline function exported by
libjoe. How is that enforced? Is it by the compiler or the linker?

It's a constraint violation: "An inline definition of a function with
external linkage ... shall not contain a reference to an identifier
with internal linkage." (6.7.4p2) This "shall" occurs in a
"Constraints" section, so a diagnostic is required. This constraint
can be diagnosed at compile time; there's no need to wait for link
time before issuing the diagnostic.
 
U

user923005

Hi all,

Im very confused about how you should provide inline functions in a
library. Lets say the library is libjoe with headerfile <joe.h>. There
seem to be a few possibilities:

1) have the function defined in joe.h as static inline.

2) have the function defined in joe.h as inline and also include
an extern inline prototype for it in joe.h. (Make sure to use #pragma once
in joe.h)

3) have the function defined as inline in one of the *.c files
that make up libjoe, and put an extern inline prototype in joe.h.

Which of these is the best?

Also I guess it shouldnt be possible to call a private function from
libjoe (ie a static function in one of the *.c files that make up libjoe)
inside an inline function exported by libjoe, even though it would be
possible to call a static function in a non-inline function exported by
libjoe. How is that enforced? Is it by the compiler or the linker?

The best way is usually to let the compiler choose.
Most compilers have some kind of option for: 'Let Mr. Compiler inline
whatever functions he wants to, wherever Mr. Compiler likes and not
inline them if Mr. Compiler does not think it is a good idea.'

Sometimes, we know better than the compiler. In that case I would use
option 1, probably.
 
K

kid joe

Option 1 works, and it allows you to avoid the restrictions on inline
functions with external linkage: it can define a modifiable object
with static storage duration, and it can refer to identifiers with
internal linkage (6.7.4p2).

Option 2 is bad, since it provides only inline definitions of the
function. "It is unspecified whether a call to the
function uses the inline definition or the external
definition." (6.7.4p6) Therefore, you risk getting a link failure if
the compiler decides to call the non-existent external definition of
the function. Also, like most #pragma's, #pragma once is non-portable.

Option 3 is bad, because joe.h is unusable everywhere except the *.c
file that contains the actual definition of the function. "For a
function with external linkage, the following restrictions apply: If a
function is declared with an inline function specifier, then it shall
also be defined in the same translation unit." (6.7.4p6). This "shall"
does not occur in a "Constraints" section, so the behavior is
undefined if you violate it.

Option 4 would be to provide an inline file scope definition of the
function in joe.h, so it has implicitly external linkage, yet also
qualfies as an inline definition. Then, in the joe.c file, declare the
function with extern before #including joe.h, thereby making it an
external defintion. This gives the compiler the choice of either using
the inline definition from joe.h, or the external definition from
joe.c, whichever it thinks will produce the best results. As a general
rule the more freedom you give your compiler, the better the code that
it can generate. You should only restrict it's options if you don't
trust it to make the right choice.


It's a constraint violation: "An inline definition of a function with
external linkage ... shall not contain a reference to an identifier
with internal linkage." (6.7.4p2) This "shall" occurs in a
"Constraints" section, so a diagnostic is required. This constraint
can be diagnosed at compile time; there's no need to wait for link
time before issuing the diagnostic.

Hi James,

Thanks for the explanations. I find this a confusing area of C99, not
covered in books like K&R and also different semantics from "that other
language"...

Cheers,
Joe
 
S

s0suk3

Option 1 works, and it allows you to avoid the restrictions on inline
functions with external linkage: it can define a modifiable object
with static storage duration,

Yes, but since he intends to put the function definition in a header
file, he probably won't get the desired effect (there will be a
different copy of the variable for each file that includes the header
file).
and it can refer to identifiers with
internal linkage (6.7.4p2).

It's unlikely that he needs to to that, also due to the fact that the
function will be placed in a header file (why would you define a
variable with static storage duration in a header file?).
Option 2 is bad, since it provides only inline definitions of the
function. "It is unspecified whether a call to the
function uses the inline definition or the external
definition." (6.7.4p6) Therefore, you risk getting a link failure if
the compiler decides to call the non-existent external definition of
the function.

Never heard of such an issue. Doesn't an inline definition also
provide an external definition? As you say below:
Option 4 would be to provide an inline file scope definition of the
function in joe.h, so it has implicitly external linkage, [...]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Option 2 looks fine to me, but remove both the "extern inline"
prototype and the #pragma directive.

Sebastian
 
J

jameskuyper

Yes, but since he intends to put the function definition in a header
file, he probably won't get the desired effect (there will be a
different copy of the variable for each file that includes the header
file).

Possibly he does want to have a different copy of the variable for
each file. He asked us "which of these is best", without giving any
details about what the function does. Option 1 does permit some things
not permitted by the other options; more importantly, the standard
goes out of its way to give permission for these things to be done -
the committee must have felt that there was some potential use for
those things, and I agree.

Please note that the modifiable object with static storage duration
need not be defined, or even declared, in the same header as the
inline function; it needn't even have the same type in all the places
where that header is #included, so long as the way it is used in the
inline function is compatible with all of the different types it
actually gets defined with.
It's unlikely that he needs to to that, also due to the fact that the
function will be placed in a header file (why would you define a
variable with static storage duration in a header file?).

Please note that the standard refers to identifiers, not just
variables. The identifier could be another function with internal
linkage. Furthermore, neither the definition, nor even a declaration,
for this identifier needs to be in the header file.

One obvious reason for defining an object or function with static
storage duration in a header file would be to ensure that it has the
same definition everywhere it is used. So why not make it a single
external definition? In the case of variables, possibly because you
want that variable to have a different value in each translation unit
- one obvious use of this would be to define a counter which keeps
track of how often the inline function is used in each module. In the
case of functions, the same could apply to any variables with static
storage duration defined in the function, but another reason for doing
so would be that the function referred to is also inline.
Never heard of such an issue. Doesn't an inline definition also
provide an external definition? As you say below:

"An inline definition does not provide an external definition for the
function," (6.7.4p6).
Option 4 would be to provide an inline file scope definition of the
function in joe.h, so it has implicitly external linkage, [...]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Implicit external linkage gives the compiler permission to make use of
an external definition defined in some other translation unit, but
does not give the compiler permission to create one in the current
translation unit. An inline function explicitly declared with "extern"
is not an inline definition (6.7.4p6), and therefore does created an
external definition.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top