无意中,我写了以下有趣的片段:
#include <iostream>
#include <cstring>
size_t strlen(const char* str) {
std::cout << "hello";
return 0;
}
int main() {
return std::strlen("sdf");
}
出乎意料的是,GCC 5.1中的输出是“hello”,这意味着我的strlen
被调用了。更有趣的是,如果我删除了return
,即只需拨打std::strlen("sdf");
来替换main,就不会打印任何内容!
我也尝试过Clang,std::strlen
调用实际函数来计算字符串长度(并且没有任何内容被打印)。这就是我期望看到的。
如何解释?是否将我自己的strlen
函数定义为未定义的行为?
答案 0 :(得分:12)
这里没有什么有趣的,只是一个函数重载和一些未定义的行为。您使用自己的版本重载了库函数std::strlen
。因为在GCC中std
的实现只是名称空间cstring
内的库函数调用,所以你得到了你看到的结果。
以下是namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using ::strlen;
...
的相关摘录:
strlen
当你删除return语句时,GCC完全优化掉调用,因为它知道grep -r 'string' filepath
是没有副作用的函数,它实际上是一个保留名称,不应该重载。我假设,编译器可能会在这里给你一个警告,但是唉,它没有,因为它不是必需的。
答案 1 :(得分:4)
根据C ++ 14 [extern.names] / 3,保留::strlen
:
使用外部链接声明的标准C库中的每个名称都保留给实现,以用作extern&#34; C&#34;链接,在命名空间std和全局命名空间中。
以及使用保留名称的效果,[reserved.names] / 2:
如果程序在保留它的上下文中声明或定义名称,除了本条款明确允许的名称外,其行为是未定义的。
所以你的程序有不确定的行为。
答案 2 :(得分:0)
您在默认的std命名空间中定义了strlen,从而覆盖了标准的。
有时调用strlen并且有时调用标准strlen的原因可能与strlen的许多实现是宏而不是函数有关。它甚至可以在汇编程序中实现。
如果是宏,则会运行标准宏。 此外,如果删除return,优化程序可以删除函数调用。你可以比较-O0。