如果我尝试编译以下C代码而不声明函数static,我会收到链接器错误:
undefined reference to '_fun'
但如果我不使它静止,它会起作用。在c ++中,没有static
关键字,它可以正常工作。
// Doesn't work
inline int fun()
{
return 3;
}
// Works
static inline int fun()
{
return 3;
}
int main(int argc, const char * argv[])
{
printf("%i", fun());
}
答案 0 :(得分:3)
C中inline
的要求由ISO C标准的第6.7.4节定义。从N1256
任何具有内部链接的函数都可以是内联函数。为一个 具有外部链接的功能,以下限制适用:如果a 函数是用 内联 函数说明符声明的,然后是它 也应在同一翻译单元中定义。如果所有的文件 翻译单元中函数的范围声明包括 没有 extern 的 内嵌 功能说明符,然后是其中的定义 翻译单元是内联定义。一个 内联定义不提供外部定义 功能,并不禁止另一个外部定义 翻译单位。内联定义提供了替代 外部定义,翻译人员可以用来实现任何调用 到同一翻译单元的功能。它没有具体说明 是否对函数的调用使用内联定义或 外部定义。
据我所知,您的定义满足所有这些要求。这样:
inline int fun()
{
return 3;
}
既是声明又是fun
的定义。如果没有inline
关键字,它将具有外部链接。
棘手的部分是最后一句:
未指定对函数的调用是否使用内联 定义或外部定义。
在这种情况下,没有外部定义。您没有说明您正在使用哪种编译器,但默认情况下gcc -std=c99 -pedantic
显然选择使用外部定义,并且由于没有一个,您会收到链接器错误。 (没有-std=c99 -pedantic
,没有链接器错误,但这是因为gcc还将inline
实现为C90之上的扩展。)
如果您只是在一个源文件中使用该函数,那么您最好还是添加static
关键字,以便为其提供内部链接。
实验表明,如果我使用-O1
,-O2
或-O3
中的任何一个进行优化编译,您的程序将正确编译,链接和运行。
C标准中的脚注似乎暗示gcc表现正常。同一部分中的示例具有类似的非static
inline
函数定义:
inline double cels(double t)
{
return (5.0 * (t - 32.0)) / 9.0;
}
接下来是:
因为 cels 具有外部链接并被引用,所以外部 定义必须出现在另一个翻译单元中(见6.9); 内联定义和外部定义是截然不同的 要么可以用于通话。
标准的意图似乎是如果inline
函数具有内部链接,则应该在使用它的源文件中仅定义一次,但如果它具有外部链接,则内联定义为替代到必须出现在别处的非内联定义。是否调用外部函数或扩展内联定义的选择留给了编译器的一时兴起。
有些问题与您的问题没有直接关系:
int fun()
应该是int fun(void)
。空括号是合法的,但它们表明该函数采用了未指定的数字和类型的参数。 void
指定它不需要参数,这就是你想要的。
如果您打算致电#include <stdio.h>
f,则需要print
;这不是可选的。
const
声明中您不希望argv
。就此而言,由于您没有引用命令行参数,因此可以编写int main(void)
。
答案 1 :(得分:0)
C99 inline
语义是微妙的 - 事实上,语言的整个部分(存储持续时间与链接,暂定和内联定义)是一团糟。
虽然inline
在包含存储类说明符(static
或extern
)的定义中充当编译器提示,并且基本上可以忽略,但如果不存在说明符,则语义会发生变化。
像inline int fun(void) { ... }
这样的定义做了两件事:
首先,它声明了一个带有外部链接的标识符,但没有提供相应的外部定义。这意味着这样的定义必须由不同的翻译单元提供,否则我们最终会得到未定义的行为(可能表现为链接失败)。
其次,它提供了内联定义,它是外部定义的替代。由于函数体在当前转换单元中可见,编译器可以使用它来内联函数或类型特化。
要获得外部定义,直到fairly recently,我认为有必要在另一个翻译单元中重复该函数定义(或伪造4行预处理器代码)。
但是,这不是必需的:单行代码 - 包含extern
说明符的函数的重新声明 - 足以使内联定义成为外部定义。
在你的例子中,这意味着要放
inline int foo(void)
{
return 42;
}
到头文件foo.h
并提供内容
foo.c
#include "foo.h"
// force definition to be external instead of inline
// I believe inline could be omitted, but it doesn't hurt
extern inline foo(void);
为什么这有用?由于C缺少模板,通用代码通常会带来性能损失,因为您需要伪造带有void*
和函数指针的泛型(或者,在更复杂的情况下,使用vtable)。
但是,只有在当前翻译单元中可以看到相关的函数定义时,足够智能的优化器才能获得模板的大部分(可能是所有)性能优势,但(在没有链接时优化的情况下)。 / p>
虽然可以通过在标头中添加static
定义来实现这一点,但这可能会将代码大小增加到不可接受的水平,就像C ++模板一样。
相比之下,使用C99 inline
函数,编译器可以自由地忽略内联定义,而不是外部定义,它甚至可以驻留在共享库中。
可以从中受益的函数的一个很好的例子是qsort()
,stdlib.h
中的内联定义和libc.so
中的外部定义。 qsort()
没有先验原因要比std::sort()
慢。