printf()
调试语句揭示了一个指向我正在传递的double类型指针,在接收端解引用时得到了不同的值 - 但仅在Microsoft Visual Studio(版本9.0)下出现。步骤非常简单: double rho=0; /* distance from the Earth */
/* ... */
for (pass = 0; pass < 2; pass++) {
/* ... */
rho = sqrt(rsn*rsn+rp*rp-2*rsn*rp*cpsi*cos(ll));
printf("\nrho from sqrt(): %f\n", rho);
/* ... */
}
/* ... */
cir_sky (np, lpd, psi, rp, &rho, lam, bet, lsn, rsn, op);
/* ... */
}
/* ... */
static void
cir_sky (
/* ... */
double *rho, /* dist from earth: in as geo, back as geo or topo */
/* ... */)
{
/* ... */
printf("\nDEBUG1: *rho=%f\n", *rho);
整个C文件在这里:
我本以为第一个printf()
显示的值应该与第二个相同,因为传递一个指向double的指针不应该导致不同的值。在GCC下,它们实际上总是相同的。在Visual Studio 32位编译下,它们始终相同。但是当这段代码在64位架构下使用Visual Studio编译时,两个double值是不同的!
https://ci.appveyor.com/project/brandon-rhodes/pyephem/build/1.0.18/job/4xu7abnl9vx3n770#L573
rho from sqrt(): 0.029624
DEBUG1: *rho=0.000171
这让人感到不安。我想知道:在计算 rho
的代码和最终传递指针的代码之间,是否存在错误的指针算术运算导致值被破坏?因此,在 cir_sky()
调用的上方添加了一个最后的 printf()
,以查看该点是否已经改变或者在调用本身的过程中被改变:
printf("\nrho about to be sent: %f\n", rho);
cir_sky (np, lpd, psi, rp, &rho, lam, bet, lsn, rsn, op);
以下是整个文件中的那行代码:
你猜怎么着?
添加printf()
修复了这个bug - 传递给rho
的指针现在可以被解引用为正确的值!
如下图所示:
https://ci.appveyor.com/project/brandon-rhodes/pyephem/build/1.0.19/job/s3nh90sk88cpn2ee#L567
rho from sqrt(): 0.029624
rho about to be sent: 0.029624
DEBUG1: *rho=0.029624
我感到困惑。
我在这里遇到了C标准的什么边缘情况?为什么仅仅在函数的顶层作用域中使用
rho
的值就能够强制微软编译器正确地保留它的值?问题在于rho
在一个块内既被设置又被使用,而Visual Studio由于C标准的某个怪癖不会在该块之外保留其值吗?我从未完全理解过这个问题。您可以在上面的AppVeyor链接中查看整个构建输出。如果问题可能是Visual Studio的调用或编译选项,那么该C文件的特定编译步骤如下:
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\Bin\amd64\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -Ilibastro-3.7.7 -IC:\Python27-x64\include -IC:\Python27-x64\PC /Tclibastro-3.7.7\circum.c /Fobuild\temp.win-amd64-2.7\Release\libastro-3.7.7\circum.obj
circum.c
libastro-3.7.7\circum.c(126) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(127) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(139) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(140) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(295) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(296) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(729) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
libastro-3.7.7\circum.c(730) : warning C4244: '=' : conversion from 'double' to 'float', possible loss of data
没有一个警告是与这个谜题相关的代码,即使有,也只是意味着浮点值可能会变得不那么精确(从约15位小数精度到7位),而不是完全改变。以下是两次编译和测试运行的输出,第一次失败,第二次因为
printf()
而成功:
https://ci.appveyor.com/project/brandon-rhodes/pyephem/build/1.0.18/job/4xu7abnl9vx3n770
https://ci.appveyor.com/project/brandon-rhodes/pyephem/build/1.0.19/job/s3nh90sk88cpn2ee
根据AppVeyor,两者都是完全相同的架构:
Environment: PYTHON=C:\Python27-x64, PYTHON_VERSION=2.7.x, PYTHON_ARCH=64, WINDOWS_SDK_VERSION=v7.0
python
的标签? - BrenBarn