![](/img/trans.png)
[英]Why does a pointer returned from strtok() cause a segmentation fault when passed to printf()?
[英]Why does a printf() allow this double to be passed by pointer?
一對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()
修復了錯誤 - 傳遞給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鏈接中看到整個構建輸出。 如果問題可能是調用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
我快速查看這段代碼並沒有提出任何突出的錯誤或有問題的東西。 但是,當printf
解決問題時,這意味着存在一些非確定性。 讓我們分析可能的原因:
rho
在這里被初始化,但是,也許其他地方的東西不是,而且它正在搞亂。 我會運行valgrind(在Linux上)和AdressSanitizer以及其他清潔劑(對於Windows也應該在clang和gcc上使用),看看他們是否想出了什么。 無論如何,我建議你在Windows機器上進行調試。 根據我的經驗,這是解決這些問題的最佳方式。
這是(錯誤)優化的影響嗎?
關閉任何優化(DEBUG?)並查看是否獲得相同的效果。
當然,如果你發現它是優化器,那么你就可以了,只能做一些事情來欺騙它,例如一個什么都不做的sprintf。
另外,printf也可以打印出指針(“%16x”,(long)&rho)而不是我認為它是不正確的,但是作為一個健全條款,以防我們缺少summat。 此外,大多數雙倍隨機位的結果通常最終在E +/- 317范圍內,因此0.000171結果有點太合理而不能完全懷疑。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.