将非静态内联函数重新声明为extern

时间:2018-10-29 08:07:48

标签: c language-lawyer

在内部范围中将内联函数重新声明为extern是否合法?

下面的代码在MACRO是否为真的情况下是否为合法C?

#if MACRO
    enum { have_macro = 1 };
    inline int foo(void){ return 43; }
#else
    enum { have_macro = 0 };
#endif
int main()
{
    if(have_macro){
        extern int foo(void);
        return foo();
    }else
        return 0;
}
extern int foo(void); //maybe instantiate

3 个答案:

答案 0 :(得分:3)

  

在内部范围中将内联函数重新声明为extern是否合法?

是的,但是如果您在其他翻译单元中也没有内联地定义它,那么使用哪个是不确定的。

  

在类似的主题上,我可以通过在另一个文件中声明extern来与实例化的非静态内联链接吗?

否,内联函数仅对在其中声明和定义的编译单元可见。

  

6.7.4函数说明符

     
      
  1. 任何具有内部链接的函数都可以是内联函数。 对于具有外部链接的功能,   适用以下限制:如果函数是用内联函数说明符声明的,则它将   如果函数中的所有文件范围声明都在   一个翻译单元包括没有extern的内联函数说明符,然后是其中的定义   翻译单元是内联定义。 内联定义不提供外部定义   该功能,并且不禁止在另一个翻译单元中使用外部定义。内联   定义提供了外部定义的替代方法,翻译人员可以使用它来实现   在同一翻译单元中对函数的任何调用。不确定是否对函数进行调用   使用内联定义或外部定义。
  2.   

答案 1 :(得分:3)

非语言律师的初步说明:C中的术语外部定义不应与extern外部链接混淆。粗略地讲,它意味着“出现在文件范围而不是内联定义的任何定义”。例如,静态函数定义将是外部定义。有关更详细的介绍,请参见C17标准的6.9节。

还请注意,内联定义一词有其独特之处;带有inline关键字的函数定义可以是内联定义外部定义,具体取决于我将在下面介绍的其他内容。


对于以下代码(由MACRO定义):

inline int foo(void){ return 43; }
int main()
{
    if(1){
        extern int foo(void);
        return foo();
    }else
        return 0;
}
extern int foo(void);

第一行提供foo外部定义,而不是内联定义:

规则是,如果存在具有inline关键字的具有外部链接的函数的定义,该函数的文件范围声明不包含{{1} }关键字,则函数定义是外部定义。几乎所有的确切示例,请参见C17 6.7.4 / 10。块范围声明没有区别。

到目前为止,此代码还可以,但是,如果另一个翻译单元也为inline提供了外部定义,则将是未定义的行为。


对于没有MACRO的版本:

foo

到目前为止,这段代码还不错,但是如果某个地方程序中没有int main() { if(0){ extern int foo(void); return foo(); }else return 0; } extern int foo(void); 函数的一个确切定义,那将是未定义的行为。 (C17 6.9 / 5)隐藏在foo后面的代码并没有脱离一个定义规则。

答案 2 :(得分:-1)

inline在语言语法级别没有任何作用,它不会更改功能签名,链接或可见性。

extern是一个声明,您必须使用与定义相同的签名来声明该函数。 inline不会影响功能签名和可见性,只有static会影响功能签名和可见性。

只要您在同一翻译单元中没有违反one definition rule,就可以了。如果多个单元输出相同的弱定义,则在链接或加载时随机选择一个。