Пара инструкций отладки 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 находится здесь:
Я бы ожидал, что значение, отображаемое в первом printf()
, будет таким же, как показанное вторым, поскольку передача указателя на double не должна приводить к другому значению. И под GCC они, по сути, всегда одинаковы. В 32-битной компиляции Visual Studio они всегда одинаковы. Но когда этот код скомпилирован с Visual Studio под 64-битной архитектурой, два двойных значения отличаются друг от друга!
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
, и где, наконец, передается указатель, каким-то образом уничтожает значение с помощью арифметики с плохим указателем? Поэтому я добавил последний printf()
, прямо над вызовом cir_sky()
, чтобы узнать, было ли это значение уже изменено этой точкой или было ли оно изменено в ходе самого вызова:
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 выше. Конкретный шаг компиляции для этого файла 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
Ни одно из этих предупреждений, из того, что я вижу, для кода, участвующего в этой конкретной головоломке, - и даже если бы они были, все, что они означали бы, это то, что значение float может стать менее точным (примерно от 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