当我试图理解内联函数时,我发现自己陷入了一个非常深的兔子洞。我知道了
inline
是一个函数说明符,即
内联
这只是对编译器的一个提示,编译器是否执行内联扩展取决于编译器,编译器需要一个定义
内联
以及正常函数调用的另一个定义等。
顺便说一句,考虑到这里的问题数量,似乎我并不是唯一一个很难理解这个话题的人。尽管我试着读这些答案,但我仍然觉得很神秘。
然而,我确信有两种正确的方法来使用内联函数,它们是
static inline
和
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
与此同时,我尝试了下面的代码,得到了
奇怪的结果
,这就是本问题的主题。
/* 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);
}
我写了两个版本的
fn
功能,我故意让它们不同。(
fn
在test2.c中只有一个参数
fn
在test1.c中有两个参数。)
在我编译并执行这个程序后,每次运行它时,它都会打印一个随机数。
$ gcc -o test test_1.c test_2.c
$ ./test
-1466335670
$ ./test
81565994
据我猜测
fn(123)
test2.c中的调用使用了以下定义
fn
在test1.c中,因为编译器需要一个正常的定义
fn
因为它没有选择内联它,以及
fn
具有外部联系。(如果一个函数有外部链接,则该函数可以从其他文件中看到。)同时,编译器似乎可以识别
fn
由于
fn
test_2.c中的定义。然而,
fn(123)
缺少第二个参数。所以我认为事情出了问题,因为这个原因。或者,也许只是因为我写了一段代码,导致了未定义的行为或其他什么。
很抱歉再加一个“我不理解在线功能”的问题,但请再慷慨地给我一个。如果您能解释一下为什么会发生这种情况,我们将不胜感激。非常感谢。
编辑
:这是我构建可执行文件的环境。注意:我使用的是Windows 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
这是我用来构建可执行文件的命令。
$ gcc -o test test_1.c test_2.c
如果可能的话,我更喜欢C99,因为我学习C的那本书解释了C89&C99。非常感谢。