c – 为什么printf()允许这个double被指针传递?

前端之家收集整理的这篇文章主要介绍了c – 为什么printf()允许这个double被指针传递?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
一对printf()调试语句显示,指向我的双精度指针是在接收端解除引用时以不同的值出现,但仅在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文件在这里:

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.029624

DEBUG1: *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.029624

rho about to be sent: 0.029624

DEBUG1: *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.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

没有一个这样的警告,从我可以看到,代码涉及到这个特定的难题 – 即使是这样,他们所表示的只是浮动值可能会变得不那么精确(从十进制精度的十五位数到七),而不是完全可以改变.

这里再次是两个编译和测试运行的输出,其中第一个失败,其中第二个是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&C++相关文章