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 voIDcir_sky (/* ... */double *rho,/* dist from earth: in as geo,back as geo or topo *//* ... */){ /* ... */ printf("\nDEBUG1: *rho=%f\n",*rho);
整个C文件在这里:
https://github.com/brandon-rhodes/pyephem/blob/9cd81a8a7624b447429b6fd8fe9ee0d324991c3f/libastro-3.7.7/circum.c#L366
我预计第一个printf()中显示的值将与第二个printf()中显示的值相同,因为将指针传递给double不应导致不同的值.事实上,在海湾合作委员会下,它们总是具有相同的价值.在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.029624DEBUG1: *rho=0.000171
这是令人不安的.我想知道:Rho计算的代码和指针最后通过的代码是否以坏指针算术方式破坏了值?所以我在cir_sky()调用之上添加了最后一个printf(),以查看该值是否已被修改,或者是否在调用过程中被更改:
printf("\nrho about to be sent: %f\n",rho); cir_sky (np,op);
这是在整个文件的上下文中的那行:
https://github.com/brandon-rhodes/pyephem/blob/28ba4bee9ec84f58cfffabeda87cc01e972c86f6/libastro-3.7.7/circum.c#L382
你猜怎么着?
添加printf()修复错误 – 传递给rho的指针现在可以被取消引用到正确的值!
从这里可以看出:
https://ci.appveyor.com/project/brandon-rhodes/pyephem/build/1.0.19/job/s3nh90sk88cpn2ee#L567
rho from sqrt(): 0.029624rho about to be sent: 0.029624DEBUG1: *rho=0.029624
我很神秘
我进入这个C标准的哪个边缘案例?为什么只使用此函数的顶级范围中的值rho来强制Microsoft编译器正确保留其值?是否在一个块内部设置和使用rho的问题,Visual Studio不会将其值保留在该块之外,因为C标准的奇怪,我从未完全内化?
您可以在上面的appveyor链接中查看整个构建输出.这个C文件的特定编译步骤,如果问题可能是如何调用Visual Studio或编译选项,则是:
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.objcircum.clibastro-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 datalibastro-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 datalibastro-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
没有一个这样的警告,从我可以看到,代码涉及到这个特定的难题 – 即使是这样,他们所表示的只是浮动值可能会变得不那么精确(从十进制精度的十五位数到七),而不是完全可以改变.
这里再次是两个编译和测试运行的输出,其中第一个失败,其中第二个是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解决方法 我快速看看这个代码没有出现任何突出的错误或有问题的东西.但是,当printf解决问题时,这意味着存在一些非确定性存在.我们分析可能的原因:
>并发 – 数据竞赛:最常见的,但你说它是单线程的.
>未初始化的内存:rho在这里被初始化,但也可能是其他地方没有的东西,它是搞砸的.我会运行valgrind(在linux上)和AdressSanitizer和其他消毒剂(应该可以在clang和gcc for windows),看看他们想出了什么.
>野生指针和其他超出限制的访问:我们在这里看到的代码中没有任何内容,但它正在调用其他函数.再次运行valgrind和消毒剂.
>如果以前的步骤很简单,下一个最可能的候选者是MSVC错误. MSVC臭名昭着的是在一些复杂的代码中解决问题,这有点复杂.很多时候我重新排列代码只是为了让MSVC快乐.有时关闭优化有助于,有时它不会.同样尝试不同的编译器选项.有时候有一个更新/补丁可以帮助,有时没有.同上,下一个版本的MSVC.我建议在调试器中查看反汇编程序,但是您说您无法访问windows机器.这里最好的办法是尝试简化代码 – 使功能更小,减少参数数量.
>还有其他可能的原因.例如,也许堆栈由于某些原因而被搞砸了 – 也许当与Python运行时交互时.尝试建立&运行它作为“常规”C代码,而不是Python扩展.消除对其他功能的调用(如果它弄乱了计算,没关系,你只是想找出问题).
在任何情况下,我建议你把手放在windows机器上并进行调试.根据我的经验,这是解决这些问题的最佳途径.
总结以上是内存溢出为你收集整理的c – 为什么printf()允许这个double被指针传递?全部内容,希望文章能够帮你解决c – 为什么printf()允许这个double被指针传递?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)