具有外部链接的内联函数定义,其中包含对静态对象的引用

时间:2019-05-10 13:01:45

标签: c language-lawyer inline-functions

有一个约束6.7.4(p3)

  

具有外部链接的函数的内联定义不应   包含带有静态或线程的可修改对象的定义   存储期限,并且不得包含对标识符的引用   具有内部链接。

考虑以下示例:

static const int i = 10;

void do_print(void);

inline void do_print(void){
    printf("%d/n", i); //Reference to an identifier with internal linkage
                       //constraint violation
}

DEMO

此处,具有外部链接的函数的内联定义使用具有内部链接的标识符。因此,根据5.1.1.3(p1)

  

符合标准的实现 应至少产生一个诊断    消息 (以实现定义的方式标识),如果   预处理翻译单元或翻译单元包含一个   违反任何语法规则或约束,即使行为是   也明确指定为未定义或实现定义。

我希望编译器以某种方式报告违反此约束的情况(警告)。但是代码编译得很好,没有警告或产生其他消息。

问题是 :在上述约束违反的情况下,为什么不生成诊断消息?

2 个答案:

答案 0 :(得分:4)

cppreference的一段解释了其背后的原因:

  

如果某个函数在某些翻译单元中被内联声明,则不必在任何地方都内联声明:最多一个翻译单元还可以提供一个常规的非内联非静态函数,或一个被声明为extern inline的函数。据说该翻译单元提供了外部定义。如果在表达式中使用具有外部链接的函数的名称,则程序中必须存在一个外部定义。

     

如果程序中存在外部定义,则函数的地址始终是外部函数的地址,但是当使用该地址进行函数调用时,不确定内联定义(如果存在于翻译中)单元)或调用外部定义。

也有一条字样(强调我的意思):

  

inline关键字是从C ++采用的,但是在C ++中,如果将函数声明为内联,则必须在每个翻译单元中将其声明为内联,并且内联函数的每个定义都必须完全相同( C,只要程序的行为不取决于差异,定义可能会有所不同)。另一方面,C ++允许非常量函数局部静态变量,并且来自内联函数不同定义的所有函数局部静态变量在C ++中相同,而在C中则不同。

这意味着,如果本地内联函数在一个转换单元中使用static const value,则可以在不同的转换单元中定义具有相同名称的非内联函数,且其静态const变量的值将不同,从而导致明确的UB,因为未指定编译器是否将使用全局非内联版本的本地内联。

答案 1 :(得分:4)

  

问题是:为什么在上述约束违反的情况下没有产生诊断消息?

因为您的编译器在这方面不合格。

这就是全部。您已经正确分析了标准文本,并将其正确应用于显示的代码。合格的实现必须通过i的内联实现发出有关对变量do_print的引用的诊断。因此,并非完全不合格。

在这一点上,我注意到一些编译器在一般情况下是不合格的,默认情况下会省略必需的诊断,同时提供了打开这些强制诊断的选项。例如,这就是GCC中-pedantic选项的功能。但是,我发现即使指定了-pedantic,我的GCC版本(有些过时)也不会警告您的代码。

相关问题