chm*_*lig 29 c++ linker compilation language-lawyer undefined-function
可能令人惊讶的是,这个C++代码打印出来1.
#include <iostream>
std::string x();
int main() {
std::cout << "x: " << x << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
x 是一个函数原型,它似乎被视为一个函数指针,而C++标准部分4.12布尔转换说:
4.12布尔转换[conv.bool] 1算术,无范围枚举,指针或指向成员类型的指针的prvalue可以转换为bool类型的prvalue.零值,空指针值或空成员指针值转换为false; 任何其他值都转换为true.对于直接初始化(8.5),std :: nullptr_t类型的prvalue可以转换为bool类型的prvalue; 结果值为false.
但是,x永远不会绑定一个函数.正如我所料,C链接器不允许这样做.但是在C++中,这根本不是问题.谁能解释这种行为?
M.M*_*M.M 28
这里发生的是函数指针被隐式转换为bool.这由[conv.bool]以下内容指定:
将零值,空指针值或空成员指针值转换为
false; 任何其他值都转换为true
其中"空指针值"包括空函数指针.由于从函数名称的衰减中获得的函数指针不能为空,因此给出了true.您可以通过<< std::boolalpha在输出命令中包含来看到这一点.
以下确实导致g ++中的链接错误: (int)x;
关于是否允许这种行为,C++ 14 [basic.odr.ref]/3说:
如果函数的唯一查找结果或一组重载函数的选定成员[...],则其名称显示为可能已评估的表达式的函数将被使用.
这涵盖了这种情况,因为x在输出表达式中查找了x 上面的声明,这是唯一的结果.然后/4我们有:
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; 无需诊断.
所以程序结构不合理,但不需要诊断,这意味着程序的行为是完全未定义的.
顺便说一句,这条款意味着x();从实施质量角度来看,两者都不需要链接错误; 那会很傻.g++这里选择的课程对我来说似乎是合理的.
Fre*_*pin 13
X不需要"绑定"到函数,因为您在代码中声明存在此类函数.因此编译器可以安全地假设该函数的地址不能为NULL.为了实现这一点,你必须声明函数是一个弱符号,而你却没有.链接器没有抗议,因为你从不调用你的函数(你从不使用它的实际地址),所以它没有看到任何问题.
[basic.def.odr]/2:
如果它是唯一查找结果或一组重载函数的选定成员(3.4,13.3,13.4),则其名称显示为可能已评估的表达式的函数将使用odr,除非它是纯虚函数及其名称没有明确限定.
因此,严格来说,代码odr-使用函数,因此需要定义.
但是现代编译器会意识到函数的确切地址实际上并不与程序的行为相关,因此会忽略使用而不需要定义.
另请注意[basic.def.odr]/3指定的内容:
每个程序应该只包含该程序中使用的每个非内联函数或变量的一个定义; 无需诊断.
实现没有义务停止编译并发出错误消息(=诊断).它可以做到它认为最好的.换句话说,任何行动都是允许的,我们有UB.