Is it "built-in" without the "static" or "external" ever useful in C99?

When I try to create this code

inline void f() {} int main() { f(); } 

using the command line

 gcc -std=c99 -oa ac 

I get a linker error (undefined reference to f ). The error disappears if I use static inline or extern inline instead of just inline , or if I compile with -O (so the function is actually inline ).

This behavior appears to be defined in clause 6.7.4 (6) of standard C99:

If all declarations of the scope for a function in a translation block include an inline function specifier without extern , then the definition in this translation block is a built-in definition. The built-in definition does not provide an external definition of a function and does not prohibit an external definition in another translation unit. The built-in definition provides an alternative to an external definition that the translator can use to implement any function call in the same translation unit. It is not indicated whether the function call uses the built-in definition or the external definition.

If I understand everything correctly, a compilation unit with a specific inline function, as in the above example, only compiles sequentially if there is also an external function with the same name, and I never know whether my own function belongs or the external function is called.

Isn't that really stupid? Is it ever useful to define an inline function without static or extern in C99? Did I miss something?

Summary of responses

Of course, I missed something, and the behavior is not stupid. :)

As Nemo explains , the idea is to put a function definition

 inline void f() {} 

in the header file and only declaration

 extern inline void f(); 

in the corresponding .c file. Only an extern declaration triggers the generation of external visible binary code. Indeed, there is no use of inline in a .c file - this is only useful in headers.

As explained by the rationale for the C99 committee in Jonathan’s answer , inline is all about optimizing the compiler, requiring a function to be defined to be visible to the call site. This can only be achieved by placing the definition in the header, and, of course, the definition in the header should not generate code every time the compiler sees it. But since the compiler is not forced to actually embed the function, an external definition must exist.

+88
c c99 inline
Jun 10 2018-11-22T00:
source share
3 answers

Actually this excellent answer also answers your question, I think:

extern inline

The idea is that "inline" can be used in the header file, and then "extern inline" in the .c file. "extern inline" is how you instruct the compiler which object file should contain the (externally visible) generated code.

[update, clarify]

I do not think that for inline (without "static" or "extern") the .c file uses some benefit. But in the header file this makes sense, and in order to actually create stand-alone code, it requires the corresponding extern inline declaration in some .c file.

+36
Jun 10 2018-11-22T00:
source share

From the standard (ISO / IEC 9899: 1999):

Appendix J.2 Undefined Behavior

  • ...
  • An external link function is declared using the inline function specifier, but it is not defined in the same translation system (6.7.4) either.
  • ...



The C99 committee wrote Rationale , and he says:

6.7.4 Function Specifiers

New C99 function: the inline adapted from C ++ is a function specifier that can only be used in function declarations. This is useful for optimizing programs that require the definition of a function that should be visible at the call site. (Note that the standard does not attempt to indicate the nature of these optimizations.)

Visibility is guaranteed if the function has an internal connection, or if it has an external connection and the call is in the same translation unit as the external definition. In these cases, the presence of an inline keyword in the declaration or the definition of a function has no effect, other than indicating that calls to this function should be optimized in preference to calls to other functions declared without the inline .

Visibility is a problem for calling a function with external communication, where the call is in different translation units from the function definition. In this case, the inline allows the translation unit containing the call to also contain a local or inline function definition.

A program may contain a translation block with an external definition, a translation block with a built-in definition, and a translation block with an announcement, but not a definition for a function. Calls in the latter translation system will use an external definition as usual.

An internal definition of a function is considered a different definition than an external definition. If a call to a func function with an external link occurs where the built-in definition is visible, the behavior is the same as if the call was made for another function, say __func , with an internal link. The corresponding program should not depend on what function is called. This is an embedded model in the standard.

An appropriate program should not rely on an implementation using an inline definition, nor can it rely on an implementation using an external definition. The address of the function is always the address corresponding to the external definition, but when this address is used to call the function, a built-in definition can be used. Therefore, the following example may not behave as expected.

 inline const char *saddr(void) { static const char name[] = "saddr"; return name; } int compare_name(void) { return saddr() == saddr(); // unspecified behavior } 

Since the implementation can use the built-in definition for one of the saddr calls and use the external definition for the other, the equality operation is not guaranteed to evaluate to 1 (true). This shows that static objects defined inside the built-in definition are different from the corresponding object in the external definition. This motivated the restriction by defining a const object of this type.

Invalidation was added to the Standard in such a way that it can be implemented using the existing linker technology, and the C99 embedding subset is compatible with C ++. This was achieved by requiring that exactly one translation unit containing a definition of an inline function, specified as one that provides an external definition of the function. Because of this, the specification simply consists of an declaration that either does not have the inline or contains both inline and extern , it will also be accepted by the C ++ translator.

Embedding in C99 extends the C ++ specification in two ways. First, if an inline function is declared in one translation unit, it does not need to be declared inline in every other translation unit. This allows, for example, a library function, which must be built into the library, but is only accessible through an external definition elsewhere. An alternative to using a wrapper function for an external function requires an additional name; and this can also adversely affect performance if the translator does not actually perform the built-in lookup.

Secondly, the requirement that all definitions of the built-in function be "exactly the same" is replaced by the requirement that the behavior of the program does not depend on whether the call is implemented with a visible built-in definition or an external definition of the function. This allows the built-in definition to be specialized for its use in a specific translation unit. For example, an external definition of a library function may include some argument checking that is not needed for calls made from other functions in the same library. These extensions have some advantages; and programmers who are concerned about compatibility might just abide by the stricter C ++ rules.

Note that built-in standard definitions of library functions in standard headers are not suitable for implementations, because this can break some inherited code that overrides standard library functions after including their headers. The inline intended only to provide users with a portable way to offer feature embedding. Since standard headers should not be portable, implementations have other options in accordance with:

 #define abs(x) __builtin_abs(x) 

or other non-portable mechanisms for embedding standard library functions.

+22
Jun 10 2018-11-22T00:
source share

> I get a linker error (undefined link to f )

Works here: Linux x86-64, GCC 4.1.2. May be a bug in your compiler; I do not see anything in the cited paragraph from the standard that prohibits this program. Note the use of if, not iff .

The built-in definition provides an alternative to the external definition that the translator can use. to implement any function call in the same translation unit.

So, if you know the behavior of the function f , and you want to call it in a narrow loop, you can copy its attachment to the module to prevent function calls; or you can provide a definition that is equivalent for the purposes of the current module (but skips input validation or any optimization you can imagine). However, the compiler developer has the ability to optimize the size of the program.

0
Jun 10 2018-11-22T00:
source share



All Articles