While I tried to understand inline functions, I found myself in a rabbit hole which is very deep. I get to know that inline is a function specifier, that inline is a mere hint to a compiler, that it's up to a compiler whether it perform an inline expansion or not, that a complier needs one definition for inline and another definition for a normal function call, etc.
By the way, it seems I'm not the only one who is having a hard time trying to understand this topic, considering the number of questions on it here. Even though I've tried to read those answers, I still feel cryptic.
Nevertheless, what I'm sure is that there are two correct ways to use inline functions, which are static inline and extern inline:
/* Usage of static inline */ /* This is a file named test.c */ #include <stdio.h> static inline int fn(void); int main(void) { printf("%d\n", fn()); return 0; } // Does this provide two definitions? I'm not sure. static inline int fn(void) { return 123; } /* Output */ $ gcc -o test test.c $ ./test 123 /* Usage of extern inline */ /* In a file named inline.h */ inline int fn(void) { return 321; } /* In a file named inline.c */ #include "inline.h" // So this "declaration" is treated as "definition"? extern int fn(void); /* In a file named test.c */ #include <stdio.h> #include "inline.h" int main(void) { printf("%d\n", fn()); return 0; } /* Output */ $ gcc -o test test.c inline.c $ ./test 321 Meanwhile, I gave it a try the below code and I got a bizarre result, which is the topic of this question.
/* In a file named test_1.c */ #include <stdio.h> inline int fn(int a, int b) { return a + b; } extern int fn(int a, int b); int wrapper(void); int main(void) { printf("%d\n", wrapper()); return 0; } /* In a file named test_2.c */ inline int fn(int a) { return a; } int wrapper(void) { return fn(123); } I wrote two versions of the fn function and I purposely made them different. (fn in test_2.c has only one parameter while fn in test_1.c has two parameters.)
After I compiled this program and executed it, it printed a random number every time I ran it.
$ gcc -o test test_1.c test_2.c $ ./test -1466335670 $ ./test 81565994 As far as I guess, the fn(123) call in test_2.c used the definition of fn in test_1.c since the compiler needed a normal definition of fn because it didn't choose to inline it, and fn has an external linkage. (If a function has an external linkage, that function is visible from other files.) Meanwhile, it seems the compiler recognized fn has only one parameter because of the fn definition in test_2.c. However, fn(123) lacked of the second parameter. So I think something went wrong because of this reason. Or perhaps it's just because I wrote a code causing undefined behaviors or something.
I'm sorry to add one more 'I-don't-understand-inline-functions' question, but please give me one more generosity. It would be greatly appreciated if you could explain why this happens. Thank you.
EDIT: This is the environment on which I built the executable. Note: I'm using Windows Subsystem for Linux (WSL).
> wsl -l -v NAME STATE VERSION * Ubuntu Running 2 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy $ gcc --version gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 This is the commands I used to build the executable.
$ gcc -o test test_1.c test_2.c If possible, I would prefer C99, since the book from which I learned C explains C89 & C99. Thank you very much.
-std=c99. The default for your version of GCC isgnu17which is ISO C17 plus GCC-specific extensions. Alternatively, you could get a newer book (or simply be assured that the majority of what you're learning about C99 is still applicable to C11/C17/C23).test_2, in which case you are calling the code intest_1, and with the wrong number of arguments. Clearly, no good can come of that. Were you perhaps expecting a compiler error? Most C implementations can't do any type checking across translation units, and so have no way to detect such an error at compile or link time..cfile to have a "different inline" function with the same name when one.cfile has anexterndeclaration of a function with that name. I think this question is just a kind of random curiosity which occurs suddenly when trying to get the hang of something. Yes, maybe I expected a compile error..cfile can have its own (possibly different) definition of astatic inlinefunction with the same name. (Since that's the meaning ofstatic.) (2) In the normal usage ofextern inline, each.cfile includes.hfile where the inline definition of a function is. So I thought it's fine for each.cfile to have the same "inline" function definition, unlike normal function definitions. I think it causes a compile error to have multiple definitions of a function.