手动定义的 strlen 的奇怪行为
Weird behavior with a manually defined strlen
一不小心,我写了以下有趣的片段:
#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
函数是否被视为未定义行为?
这里没有什么有趣的东西,只是一个函数重载和一些未定义的行为。您使用自己的版本重载了库函数 strlen()
。由于在 GCC 中 std::strlen
的实现只不过是命名空间 std
内的库函数调用,所以您会得到所看到的结果。
这里是来自cstring
的相关摘录:
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using ::strlen;
...
并且当您删除 return 语句时,GCC 会完全优化调用,因为它知道 strlen
是没有 side-effects 的函数,它实际上是一个保留名称,不应超载。我想,编译器可能会在这里给你一个警告,但是,唉,它没有,因为它不是必需的。
您在默认的 std 命名空间中定义了 strlen,从而覆盖了标准命名空间。
之所以有时会调用您的strlen,有时会调用标准的strlen,可能与这样一个事实有关,即许多strlen 的实现是宏而不是函数。它甚至可以在汇编程序中实现。
如果是宏,则标准宏会 运行。
此外,如果您删除 return,优化器可以删除函数调用。您可以与 -O0.
进行比较
根据 C++14 [extern.names]/3,::strlen
被保留:
Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
以及使用保留名称 [reserved.names]/2 的效果:
If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
所以你的程序有未定义的行为。
一不小心,我写了以下有趣的片段:
#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
函数是否被视为未定义行为?
这里没有什么有趣的东西,只是一个函数重载和一些未定义的行为。您使用自己的版本重载了库函数 strlen()
。由于在 GCC 中 std::strlen
的实现只不过是命名空间 std
内的库函数调用,所以您会得到所看到的结果。
这里是来自cstring
的相关摘录:
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using ::strlen;
...
并且当您删除 return 语句时,GCC 会完全优化调用,因为它知道 strlen
是没有 side-effects 的函数,它实际上是一个保留名称,不应超载。我想,编译器可能会在这里给你一个警告,但是,唉,它没有,因为它不是必需的。
您在默认的 std 命名空间中定义了 strlen,从而覆盖了标准命名空间。
之所以有时会调用您的strlen,有时会调用标准的strlen,可能与这样一个事实有关,即许多strlen 的实现是宏而不是函数。它甚至可以在汇编程序中实现。
如果是宏,则标准宏会 运行。 此外,如果您删除 return,优化器可以删除函数调用。您可以与 -O0.
进行比较根据 C++14 [extern.names]/3,::strlen
被保留:
Each name from the Standard C library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.
以及使用保留名称 [reserved.names]/2 的效果:
If a program declares or defines a name in a context where it is reserved, other than as explicitly allowed by this Clause, its behavior is undefined.
所以你的程序有未定义的行为。