我有以下名为 test.cpp 的 C++ 测试程序:
#include <cmath>
#include <iostream>
double sqrt(double d) { return std::sqrt(d); }
int main()
{
std::cout << "sqrt(4): " << sqrt(4) << std::endl;
}
这是一些相当人为的代码,正如您可能已经猜到的那样,我只是在尝试使用 Stroustrup 进行练习。他声明了 double sqrt(double),并希望读者定义它。
我使用 g++ 4.8(来自 Qt 5.1 的 MINGW 版本)编译了上面的代码:
C:\Windows\Temp>g++ -o test.exe -g test.cpp
当我运行生成的可执行文件时,Windows 7 显示“test.exe 已停止工作”。
为了看看出了什么问题,我在 GNU 调试器中运行了 test.exe。调试器命令和输出:
C:\Windows\Temp>gdb -q test.exe
Reading symbols from C:\Windows\Temp\test.exe...done.
(gdb) b main
Breakpoint 1 at 0x401625: file test.cpp, line 8.
(gdb) run
Starting program: C:\Windows\Temp\test.exe
[New Thread 12080.0x2ba0]
Breakpoint 1, main () at test.cpp:8
8 std::cout << "sqrt(4): " << sqrt(4) << std::endl;
(gdb) s
sqrt (d=4) at test.cpp:4
4 double sqrt(double d) { return std::sqrt(d); }
(gdb) s
sqrt (d=4) at test.cpp:4
4 double sqrt(double d) { return std::sqrt(d); }
(gdb) s
sqrt (d=4) at test.cpp:4
4 double sqrt(double d) { return std::sqrt(d); }
(gdb) s
sqrt (d=4) at test.cpp:4
4 double sqrt(double d) { return std::sqrt(d); }
(gdb) q
A debugging session is active.
Inferior 1 [process 12080] will be killed.
Quit anyway? (y or n) y
C:\Windows\Temp>
从行为和警告中,我推断 std::sqrt 必须从全局命名空间调用 sqrt ——这导致我的函数被重复调用。
通过更改我的 sqrt 函数的名称或将其放在命名空间中,可以很容易地解决不需要的递归。但我想了解为什么 std::sqrt 以调用 ::sqrt 的方式实现。我认为 std 命名空间的全部意义在于防止名称与用户代码中的非限定名称发生冲突。
我查看了<cmath> 的 GNU 实现的源代码。但是,在链中跟踪了几个#include 之后,我失去了踪迹。也许你可以更清楚地理解它:
00052 #include <math.h>
00053
00054 // Get rid of those macros defined in <math.h> in lieu of real functions.
....
00076 #undef sqrt
....
00081 namespace std
00082 {
....
00393 using ::sqrt;
00394
00395 inline float
00396 sqrt(float __x)
00397 { return __builtin_sqrtf(__x); }
00398
00399 inline long double
00400 sqrt(long double __x)
00401 { return __builtin_sqrtl(__x); }
00402
00403 template<typename _Tp>
00404 inline typename __enable_if<double, __is_integer<_Tp>::_M_type>::_M_type
00405 sqrt(_Tp __x)
00406 { return __builtin_sqrt(__x); }
....
00437 }
顺便说一句,这不仅仅是一个 GNU 难题。使用 Visual C++ 编译器而不是 g++ 编译会产生以下警告:
C:\Windows\Temp>cl /nologo /EHsc test.cpp
test.cpp
c:\windows\temp\test.cpp(4) : warning C4717: 'sqrt' : recursive on all control
paths, function will cause runtime stack overflow
我想这使得在 StackOverflow 上提出这个问题是一个公平的问题。:)
运行生成的可执行文件会导致预期的结果:“test.exe 已停止工作”。