5

It looks extremely weird, but I was unable to compile following simple code:

inline void inline_func() {} static inline void static_inline_func() {} void some_func() { // THERE IS A PROBLEM with "inline" function inline_func(); // THERE IS NO PROBLEM with "static inline" function static_inline_func(); } int main(int argc, char *argv[]) { some_func(); return 0; } 

Compiler simply produces error:

$ gcc -Wall -o main main.c /usr/bin/ld: /tmp/ccs7lKMm.o: in function `some_func': main.c:(.text+0x15): undefined reference to `inline_func' collect2: error: ld returned 1 exit status 

I tried this code also with Clang compiler and got similar problem.

Edit

I don't think this question is a duplicate. It isn't a question about the difference between inline and static inline. This question is about the reason why an inline function cannot be compiled by some compilers while it is compiled by others (see comments).

Edit

This code can be compiled without errors using the -Os optimization argument:

$ gcc -Wall -Os -o main main.c 
11
  • I was able to reproduce this issue on gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1). Commented Jan 15, 2024 at 15:51
  • 1
    On Godbolt gcc 9.4 does not issue any error. So it's probably a specific issue on your machine (unfortunately I cannot help further). Commented Jan 15, 2024 at 15:53
  • First inline is just a suggestion to compiler, and does not guarantee it. Second, static functions have internal linkage, meaning they are only visible within the translation unit(source file) where they are defined. But non-static functions have external linkage, meaning they can be accessed from other translation units. This introduces additional complexity/limitations for the compiler when it comes to inlining. Commented Jan 15, 2024 at 15:56
  • 1
    @wohlstad: You only compiled the code and didn't link it. If you link it you will see the error. Commented Jan 15, 2024 at 16:27
  • 4
    Unrelated, but remember that in C, a function with no arguments ought to be declared as void inline_func(void). Declaring as void inline_func(); simply does not specify the type or number of arguments. Commented Jan 15, 2024 at 16:34

2 Answers 2

5

why an inline function cannot be compiled by some compilers

Inline is magic. When you use inline (without extern or static), you are required by the C programming language specification to provide two definitions of the function - one inline definition that you provided, and the other external definition of the same function. Compiler is free to choose either function - the inline or external version of it.

The inline function code you posted cannot be compiled by some compilers, because some compilers choose to use the external definition of the function. You did not provide it. Because you failed to adhere to the rules of C programming in the standard by breaking the requirement of providing two definitions of the function, your code is invalid. You have to provide the external definition of the inline functions, for example by compiling a separate file and linking with it.

Because today's compilers when compared to 30 years ago are ridiculously fast, sole inline is rather archaic and doesn't make much sense. Use static when you want your function to be inlined. Compiler will inline function no matter if you use inline or not, and he will do better decisions which functions to inline than you. (I use inline in static inline to silence compiler warnings about unused functions in gcc).

From https://en.cppreference.com/w/c/language/inline :

If a function is declared inline in some translation units, it does not need to be declared inline everywhere: at most one translation unit may also provide a regular, non-inline non-static function, or a function declared extern inline. This one translation unit is said to provide the external definition. In order to avoid undefined behavior, one external definition must exist in the program if the name of the function with external linkage is used in an expression, see one definition rule.

Sign up to request clarification or add additional context in comments.

8 Comments

Sorry, but I don't agree with this answer. You wrote that there are two definitions of the function - one inline definition that your provided, and other external definition of the same function. However, my code compiles with an error. that is, the compiler selects the `external definition', but does not generate it. IMHO, this is exclusively a malfunction of the compilers. An interesting fact is that sometimes this code can compile without error on the same compiler vendor.
The sentence states, that "inline means" that there are two definitions. You did not provide one of then, so your code is breaking contract with the compiler. I have rewritten the sentence by stating the requirement. An interesting fact Compilers are only required to act predictably with valid code. When the input code is invalid, there are no requirements (i.e. the definition of "undefined behavior") and compilers can do anything and change the behavior anytime.
I would agree with you if it was inline void inline_func(); but it is inline void inline_func() {};. It contains not only definition, but also an implementation. I'll think how to rewrote it. - will wait for your response/argument, thanks!
will wait for your edited answer. It contains not only definition, but also an implementation Hi, "definition" in C is "implementation", it's the same thing, see en.cppreference.com/w/c/language/function_definition . Yes, you provided the inline implementation. You did not provide the external implementation. Do you have any more question? With which parts you do not agree? Also, see undefined behavior.
Hi, I do not understand. I do not think "looking correct" is a compelling enough argument when disputing code validity. I will agree also from my experience, the inline behavior is mostly not well understood within the community. That's why the recommendation to forget about it and solely stick to static inline.
|
4

This is completely normal and correct behavior. See Is "inline" without "static" or "extern" ever useful in C99? for an explanation of what happens if you define a function as inline.

Roughly speaking, you have told the compiler that if it wishes to inline the function inline_func(), you have provided it the code with which to do so. This definition is only used for inlining, and does not by itself cause a standalone copy (or "external definition" in the language of the C standard) of the function to be emitted.

And the compiler is not required to actually inline the function where it is called; it may instead emit a call instruction. If so, then there has to be a standalone copy of the function somewhere in the program.

gcc and clang, when compiling without optimizations, will never inline a function call (unless it is declared with the non-portable always_inline attribute). It tries instead to emit a call to the standalone function, which as mentioned above, does not exist in your program. If you enable optimizations (-O) you will find that the program compiles and links successfully. (Though in other cases, even with optimization enabled, the compiler may still choose not to inline some functions, if it thinks it is not an overall gain for performance.)

The C standard allows both behaviors. C17 6.7.4p7 says "It is unspecified whether a call to the function uses the inline definition or the external definition."

To get the program to work reliably, you can add the line

extern inline void inline_func(void); 

which tells the compiler to emit a standalone copy of the function, using the same definition given above with plain inline. Then even if the compiler chooses not to inline the function call, there will exist a standalone copy that it can successfully call. Try on godbolt.

5 Comments

Thank you for your reply. But this looks like a response from the compiler vendor, not its user. The C standard allows both behaviors. C17 6.7.4p7 says "It is unspecified whether a call to the function uses the inline definition or the external definition.". Then I have a question. What version did the code in my example use? If internal, why does the linker try to find external? If external, why does the linker not generate it? Either way, it looks like a complete compiler disaster. I understand why Clang might behave this way - it's just copying GCC's behavior.
As far as I understand, neither GCC nor CLANG will change this due to legacy in C standards.
why does the linker not generate it? When compiler used internal version, the code compiled for some people. When the compiler used an external version, compilation failed. Linker doesn't "generate" external version, you have to write the external definition and compile with it..
@KamilCuk This looks more like an excuse for the compiler, rather than an explanation of why the compiler works so badly (stupidly).
the compiler works so badly I will try to oversimplify. Compilers are required to compile C code. If your code is not C, the compiler is not required to do anything sane with it. What "is C" and what is "not C", is defined by the C standard language specification. If your code breaks a rule in the C standard language specification, it is no longer C language, so compilers can do anything with them. In other words, by breaking a rule in C standard, your code has undefined behavior, and there are no requirements on the behavior of your program or the compiler.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.