c - 具有包含对静态对象的引用的外部链接的内联函数定义
问题描述
有一个约束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
}
在这里,具有外部链接的函数的内联定义使用具有内部链接的标识符。所以根据5.1.1.3(p1)
:
如果预处理翻译单元或翻译单元包含违反任何语法规则或约束的行为,则符合要求的实现应产生至少一个诊断 消息(以实现定义的方式标识),即使该行为也明确指定为未定义或实现-定义。
我预计编译器会以某种方式报告违反此约束的情况(一些警告)。但是代码编译得很好,没有警告或产生其他一些消息。
问题是:为什么在违反上述约束的情况下不产生诊断消息?
解决方案
cppreference有一段解释了其背后的基本原理:
如果一个函数在某些翻译单元中声明为内联,则不需要在任何地方都声明为内联:最多一个翻译单元也可以提供一个常规的、非内联的非静态函数,或者一个声明为 extern inline 的函数。据说这一翻译单元提供了外部定义。如果在表达式中使用具有外部链接的函数名称,则程序中必须存在一个外部定义,请参见一个定义规则。
如果程序中存在外部定义,则函数的地址始终是外部函数的地址,但是当该地址用于进行函数调用时,未指定是内联定义(如果存在于翻译单元中)还是调用外部定义。
一个注释还说(强调我的):
inline 关键字取自 C++,但在 C++ 中,如果函数声明为 inline,则必须在每个翻译单元中声明为 inline,并且每个 inline 函数的定义必须完全相同(在 C 中,定义可能是不同,只要程序的行为不依赖于差异)。另一方面,C++ 允许非常量函数局部静态,并且来自内联函数的不同定义的所有函数局部静态在 C++ 中是相同的,但在 C 中是不同的。
这意味着,如果本地内联函数static const value
在一个翻译单元中使用 a,则可以在不同的翻译单元中定义具有相同名称的非内联函数,并且静态 const 变量的值不同,从而导致显式 UB,因为未指定是否编译器将使用全局非内联版本的本地内联。
推荐阅读
- python - 我对 python 中的 object.partition(element_to_search) 有疑问
- android - Android:仅针对某些目标共享 Intent 调用 onStop
- git - Git 错误:远程解包失败:无法创建临时对象目录 - 尝试推送到远程存储库时
- docker - Facebook 图形 API 和 Docker
- reference - 在 Blazor 中转义“@”字符
- html - 自定义所需输入
- r - 如何选择 R 中 POSIXct 类的变量名称?
- python - 无法在 WSL 上的 pipenv 中创建新的 ipykernel 内核
- laravel - Laravel Mix 和 Monaco 编辑器
- angular - Angular Material Table:提供的数据源与数组、Observable 或 DataSource 不匹配