如何解决函数调用中更改指针值的问题?这是一个cgo错误吗?
How to resolve changing pointer value in function call? Is this a cgo bug?
我这样通过cgo调用C函数:
var _outptr_7 C.double
var _outptr_8 C.double
var kk uintptr = uintptr(unsafe.Pointer(&_outptr_7))
gogsl.InitializeGslFunction(f)
_result := int32(C.gsl_integration_qags((*C.gsl_function)(unsafe.Pointer(f.CPtr())), C.double(a), C.double(b), C.double(epsabs), C.double(epsrel), C.size_t(limit), (*C.gsl_integration_workspace)(unsafe.Pointer(workspace.Ptr())), (*C.double)(&_outptr_7), (*C.double)(&_outptr_8)))
fmt.Printf("%10.10X\n",kk)
return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))
现在,kk
用于调试目的。我已经修改了 C 函数 gsl_integration_qags
以输出它接收到的第 8 个参数(即 &_outptr_7
,_<n>
从 0 开始计数!)
(为了这里的目的,InitializeGslFunction
可以忽略...)
两个值 - kk
和 C 函数输出 - 完全匹配。
但是,我得到一个 与 C 函数 returns 不同的 数字 - 它通过间接设置第 8 个参数。我确定这是正确的,我已经在 gdb 中看到了它的工作。
它看起来像这样:(省略了刚读到 (gdb)
的行,我在其中按回车键重复命令)
Breakpoint 3, qags (f=0xc20800a260, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0x782ec0, result=0xc208031e28, abserr=0xc208031e20, q=0x7ffff79ad12c <gsl_integration_qk21>)
at qags.c:479
479 *result = res_ext;
(gdb) n
480 *abserr = err_ext;
(gdb) p *result
= -4.0000000000000853
(gdb) p result
= (double *) 0xc208031e28
(gdb) n
482 if (err_ext == GSL_DBL_MAX)
485 if (error_type || error_type2)
513 double max_area = GSL_MAX_DBL (fabs (res_ext), fabs (area));
515 if (!positive_integrand && max_area < 0.01 * resabs0)
520 double ratio = res_ext / area;
522 if (ratio < 0.01 || ratio > 100.0 || errsum > fabs (area))
526 goto return_error;
535 if (error_type > 2)
540 if (error_type == 0)
542 return GSL_SUCCESS;
573 }
gsl_integration_qags (f=0xc20800a260, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0x782ec0, result=0xc208031e28, abserr=0xc208031e20) at qags.c:53
53 return status ;
54 }
// 正在从 C 函数 return 编辑正确的值 (-4.0)。
_cgo_3ce45c051e63_Cfunc_gsl_integration_qags (v=0xc208031db8) at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:241
asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:669
669 MOVQ 48(SP), DI
670 MOVQ (g_stack+stack_hi)(DI), SI
671 SUBQ 40(SP), SI
672 MOVQ DI, g(CX)
673 MOVQ SI, SP
asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:674
674 RET
runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:627
627 MOVL AX, ret+16(FP)
runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:628
628 RET
runtime.cgocall_errno (fn=0x405210 <_cgo_3ce45c051e63_Cfunc_gsl_integration_qags>, arg=0xc20805fdb8, ~r2=0) at /usr/lib/golang/src/runtime/cgocall.go:132
132 exitsyscall()
134 return errno
// cgo C 胶水即将 return 从调用到 Go 调用者
github.com/dtromb/gogsl/numint._Cfunc_gsl_integration_qags (p0=0xc20800a260, p1=0, p2=1, p3=0, p4=9.9999999999999995e-08, p5=1000, p6=0x782ec0, p7=0xc20805fe28, p8=0xc20805fe20, r1=0)
at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/:92
92 /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/: No such file or directory.
// 砰,坏了。 return val 结构中的 p7 值与进入的值不同/... _outptr_7 的位置已更改。
(gdb) p p7
= (github.com/dtromb/gogsl/numint._Ctype_double *) 0xc20805fe28
(gdb) p *p7
= 0
(gdb) n
github.com/dtromb/gogsl/numint.Qags (f=0xc20805ff58, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0xc20800a1d0, ~r7=7753968, ~r8=0, ~r9=0)
at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:75
75 fmt.Printf("%10.10X\n",kk)
C208031E28
76 return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))
(gdb) p _outptr_7
= 0
(gdb) p &_outptr_7
= (float64 *) 0xc20805fe28
// 但正确的值仍然存在。
(gdb) p
= -4.0000000000000853
那么,是什么原因呢?这里发生了什么?如何fix/workaround?
为了完整起见,这里是显示结构映射的 cgo 绑定:
void
_cgo_a9ebceabba03_Cfunc_gsl_integration_qags(void *v)
{
struct {
gsl_function* p0;
double p1;
double p2;
double p3;
double p4;
size_t p5;
gsl_integration_workspace* p6;
double* p7;
double* p8;
int r;
char __pad76[4];
} __attribute__((__packed__, __gcc_struct__)) *a = v;
char *stktop = _cgo_topofstack();
__typeof__(a->r) r = gsl_integration_qags((void*)a->p0, a->p1, a->p2, a->p3, a->p4, a->p5, (void*)a->p6, (void*)a->p7, (void*)a->p8);
a = (void*)((char*)a + (_cgo_topofstack() - stktop));
a->r = r;
}
错误的发生或不发生取决于编译的一些细节,这些细节不应影响语义 - 在调用 C 函数之前添加一行打印出 &_outptr_7 会导致它 return 正确,例如。对代码进行其他更改会将其还原,等等。
我做错了什么?还是 cgo 中的错误?
这是由于 Go 1.4 中的一个错误。已在 1.5 中修复。
我这样通过cgo调用C函数:
var _outptr_7 C.double
var _outptr_8 C.double
var kk uintptr = uintptr(unsafe.Pointer(&_outptr_7))
gogsl.InitializeGslFunction(f)
_result := int32(C.gsl_integration_qags((*C.gsl_function)(unsafe.Pointer(f.CPtr())), C.double(a), C.double(b), C.double(epsabs), C.double(epsrel), C.size_t(limit), (*C.gsl_integration_workspace)(unsafe.Pointer(workspace.Ptr())), (*C.double)(&_outptr_7), (*C.double)(&_outptr_8)))
fmt.Printf("%10.10X\n",kk)
return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))
现在,kk
用于调试目的。我已经修改了 C 函数 gsl_integration_qags
以输出它接收到的第 8 个参数(即 &_outptr_7
,_<n>
从 0 开始计数!)
(为了这里的目的,InitializeGslFunction
可以忽略...)
两个值 - kk
和 C 函数输出 - 完全匹配。
但是,我得到一个 与 C 函数 returns 不同的 数字 - 它通过间接设置第 8 个参数。我确定这是正确的,我已经在 gdb 中看到了它的工作。
它看起来像这样:(省略了刚读到 (gdb)
的行,我在其中按回车键重复命令)
Breakpoint 3, qags (f=0xc20800a260, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0x782ec0, result=0xc208031e28, abserr=0xc208031e20, q=0x7ffff79ad12c <gsl_integration_qk21>)
at qags.c:479
479 *result = res_ext;
(gdb) n
480 *abserr = err_ext;
(gdb) p *result
= -4.0000000000000853
(gdb) p result
= (double *) 0xc208031e28
(gdb) n
482 if (err_ext == GSL_DBL_MAX)
485 if (error_type || error_type2)
513 double max_area = GSL_MAX_DBL (fabs (res_ext), fabs (area));
515 if (!positive_integrand && max_area < 0.01 * resabs0)
520 double ratio = res_ext / area;
522 if (ratio < 0.01 || ratio > 100.0 || errsum > fabs (area))
526 goto return_error;
535 if (error_type > 2)
540 if (error_type == 0)
542 return GSL_SUCCESS;
573 }
gsl_integration_qags (f=0xc20800a260, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0x782ec0, result=0xc208031e28, abserr=0xc208031e20) at qags.c:53
53 return status ;
54 }
// 正在从 C 函数 return 编辑正确的值 (-4.0)。
_cgo_3ce45c051e63_Cfunc_gsl_integration_qags (v=0xc208031db8) at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:241
asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:669
669 MOVQ 48(SP), DI
670 MOVQ (g_stack+stack_hi)(DI), SI
671 SUBQ 40(SP), SI
672 MOVQ DI, g(CX)
673 MOVQ SI, SP
asmcgocall () at /usr/lib/golang/src/runtime/asm_amd64.s:674
674 RET
runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:627
627 MOVL AX, ret+16(FP)
runtime.asmcgocall_errno () at /usr/lib/golang/src/runtime/asm_amd64.s:628
628 RET
runtime.cgocall_errno (fn=0x405210 <_cgo_3ce45c051e63_Cfunc_gsl_integration_qags>, arg=0xc20805fdb8, ~r2=0) at /usr/lib/golang/src/runtime/cgocall.go:132
132 exitsyscall()
134 return errno
// cgo C 胶水即将 return 从调用到 Go 调用者
github.com/dtromb/gogsl/numint._Cfunc_gsl_integration_qags (p0=0xc20800a260, p1=0, p2=1, p3=0, p4=9.9999999999999995e-08, p5=1000, p6=0x782ec0, p7=0xc20805fe28, p8=0xc20805fe20, r1=0)
at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/:92
92 /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/: No such file or directory.
// 砰,坏了。 return val 结构中的 p7 值与进入的值不同/... _outptr_7 的位置已更改。
(gdb) p p7
= (github.com/dtromb/gogsl/numint._Ctype_double *) 0xc20805fe28
(gdb) p *p7
= 0
(gdb) n
github.com/dtromb/gogsl/numint.Qags (f=0xc20805ff58, a=0, b=1, epsabs=0, epsrel=9.9999999999999995e-08, limit=1000, workspace=0xc20800a1d0, ~r7=7753968, ~r8=0, ~r9=0)
at /home/dtrombley/go/src/github.com/dtromb/gogsl/numint/numint.go:75
75 fmt.Printf("%10.10X\n",kk)
C208031E28
76 return _result, *(*float64)(unsafe.Pointer(&_outptr_7)), *(*float64)(unsafe.Pointer(&_outptr_8))
(gdb) p _outptr_7
= 0
(gdb) p &_outptr_7
= (float64 *) 0xc20805fe28
// 但正确的值仍然存在。
(gdb) p
= -4.0000000000000853
那么,是什么原因呢?这里发生了什么?如何fix/workaround?
为了完整起见,这里是显示结构映射的 cgo 绑定:
void
_cgo_a9ebceabba03_Cfunc_gsl_integration_qags(void *v)
{
struct {
gsl_function* p0;
double p1;
double p2;
double p3;
double p4;
size_t p5;
gsl_integration_workspace* p6;
double* p7;
double* p8;
int r;
char __pad76[4];
} __attribute__((__packed__, __gcc_struct__)) *a = v;
char *stktop = _cgo_topofstack();
__typeof__(a->r) r = gsl_integration_qags((void*)a->p0, a->p1, a->p2, a->p3, a->p4, a->p5, (void*)a->p6, (void*)a->p7, (void*)a->p8);
a = (void*)((char*)a + (_cgo_topofstack() - stktop));
a->r = r;
}
错误的发生或不发生取决于编译的一些细节,这些细节不应影响语义 - 在调用 C 函数之前添加一行打印出 &_outptr_7 会导致它 return 正确,例如。对代码进行其他更改会将其还原,等等。
我做错了什么?还是 cgo 中的错误?
这是由于 Go 1.4 中的一个错误。已在 1.5 中修复。