起因是我突然发现用 GCC 不带任何编译选项来编译下面的 C 代码,会报错:
#include <stdio.h>
inline void func()
{
printf("Hello world!\n");
}
int main()
{
func();
return 0;
}
错误输出:
/usr/bin/ld: /tmp/ccdw5O1b.o: in function `main':
test.c:(.text+0xe): undefined reference to `func'
collect2: error: ld returned 1 exit status
但是,用 G++ 不带任何编译选项编译下面的 C++ 代码,正常运行:
#include <iostream>
using namespace std;
inline void func()
{
cout << "Hello world!" << endl;
}
int main()
{
func();
return 0;
}
我把 C 代码中的 func 加上 static 修饰符,可以正常编译:
#include <stdio.h>
static inline void func()
{
printf("Hello world!\n");
}
int main()
{
func();
return 0;
}
用 inline 声明 func 也可以正常编译:
#include <stdio.h>
inline void func();
void func()
{
printf("Hello world!\n");
}
int main()
{
func();
return 0;
}
编译的时候加上 -O2
选项也能正常编译。
我查了很多的博客,包括 C11 的标准文件,但是迫于理解能力,还是没能搞懂为啥会这样,所以在此请教一下大家。
附上我查的资料链接:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
https://stackoverflow.com/questions/19068705/undefined-reference-when-calling-inline-function
https://stackoverflow.com/questions/16245521/c99-inline-function-in-c-file/16245669#16245669
https://runtimeverification.com/blog/undefined-c-common-mistakes/
1
philon 2021-08-12 13:35:44 +08:00
inline 是某个内敛函数的“**定义**”,而非“**声明**”!(这种错误主要出现在高版本的 gcc 编译器中)
简而言之,你突然在 main 里调用了一个未知的函数,所以报错了。试着在调用前将函数声明一下,比如: ```c #include <stdio.h> void func() inline void func() { printf("Hello world!\n"); } int main() { func(); return 0; } ``` |
2
besto 2021-08-12 14:07:38 +08:00
1L 正解,另外你 Google 一下 C inline 就能得到结果了:https://stackoverflow.com/questions/31108159/what-is-the-use-of-the-inline-keyword-in-c/31108614
|
3
wangxn 2021-08-12 14:11:47 +08:00
看来 C 和 C++还是有很多细微的区别。
|
4
villivateur OP @philon 有没有说反?是“声明”而非“定义”?
|
5
xingheng 2021-08-12 14:27:41 +08:00
内联函数,不会压栈,编译的时候会被直接展开。
|
6
villivateur OP @xingheng 不要只看标题,麻烦看一下我的内容
|
7
fullpowers 2021-08-12 14:34:20 +08:00
C 的函数定义前需要声明,我觉得应该是这个原因
|
8
aneostart173 2021-08-12 14:56:30 +08:00 3
inline 在现代编译器里几乎没有任何作用。
|
9
gabon 2021-08-12 18:44:12 +08:00 via Android
是树莓派 tg 群里的吗,昨天刚好看到有人在问😂
|
10
philon 2021-08-12 19:10:06 +08:00 1
@villivateur 对于我这种 CET-4 都没过的人来说,想要区分`declare`和`define`还是很有挑战性的哈😂
我只是非常肤浅地以为,inline 是通知编译器要展开这段代码,但它因为没找到声明的地方就略过了,到了链接器的时候一看找不到函数原型,就抛了个`undefined reference` |
11
sosilver 2021-08-12 20:39:11 +08:00 via Android 1
看 modern c 写的,
1. inline 放到函数定义上(要 inline 需要知道函数怎么实现的),一般在头文件里。 2. 默认不会生成符号(不然多次包含会被重复定义)。 3. 需要在一个 TU 里不带 inline 声明以生成符号。 (括号内只是我的理解) |
12
dontmind 2021-08-12 23:11:59 +08:00
inline 是 c++ 先有,后来才引进 c,因为相容性问题才变了现在这样
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n633.htm >While the GCC-2.6.3 inlining facility was almost certainly modeled on the C++ inline capability there are several differences. .... >Much of this control is probably provided to get around the fact that the >loader won't collapse multiple definitions of a function to a single >instance as is done for uninitialized variables with external linkage. |
13
Huelse 2021-08-13 01:05:16 +08:00
我一直以为的是 inline 函数会被编译进调用的位置,现代编译器会判断 inline 声明的函数实现,过于复杂的话还是像其他普通函数一样进栈地址,另外 inline 可以被声明并在头文件中实现,如有错误欢迎指正~
|
14
hobochen 2021-08-13 19:54:26 +08:00
@aneostart173 你说的几乎是指 10%以下的性能差异不算性能差异?
|
15
muzuiget 2021-08-14 19:04:33 +08:00
怎么我觉得第一个例子也应该算是合法,编译器能判断上下文吧。
|
16
hxndg 2021-08-27 12:41:57 +08:00
gcc 4.8.5 没发现这个问题
gcc 4.9.2 没发现这个问题 gcc 5.3.1 发现确实存在这个问题 然后有几个小细节需要注意下: 1 inline 是建议,不是必然展开 2 如果你把 inline 放到 main 函数后面就会报几个 warning,但是能正常编译,编译器会 implicit declaration of function ‘func’ 3 inline 在前面的话,gcc -c main.c 生成的 main.o 会发现找不到 func 的定义。具体原因我就不知道了。。。 4 不要自己去给编译器的行为找合理解释。。。因为很可能解释是错的。。。。 |
17
zeroxia 2021-09-27 17:09:32 +08:00
程序员就是喜欢谁也看不起谁。本来 C 也是从 C++那边抄过来的,非又搞的和 C++不一样。
就好像理想的情况下,C++就是 C 的超集,这个世界就多简单,结果现在搞成这样。 |