我正在尝试使用NativeCall与某些C函数进行交互.
对于一种情况,我需要传入由函数更新的指针,因此它需要指向指针的指针'void**'.
我试过这样的:
class Foo
{
has Pointer $.first;
has Pointer $.last;
sub somefunc(Pointer is rw, Pointer is rw, Str) is native { * }
method myfunc(Str $arg) {
somefunc($!first, $!last, $arg);
}
}
Run Code Online (Sandbox Code Playgroud)
它不起作用.指针不会被函数更新.
由于C数组基本上是指向指针的指针,我可以这样伪造它:
class Foo
{
has Pointer $.first;
has Pointer $.last;
sub somefunc(CArray[Pointer], CArray[Pointer], Str) is native { * }
method myfunc(Str $arg) {
my $first = CArray[Pointer].new($!first);
my $last = CArray[Pointer].new($!last);
somefunc($first, $last, $arg);
$!first = $first[0];
$!last = $last[0];
}
}
Run Code Online (Sandbox Code Playgroud)
它工作得很好.看起来像"是rw"应该强制指针指针,它应该以第一种方式工作.
我究竟做错了什么?
Perl 6 文档列出了一堆类型.其中一些(例如Str)具有更复杂的盒子/拆箱行为.
是否可以定义我自己的类型,为box/unboxing指定我自己的例程?对于一个特定的项目,我有一堆我正在重用的类型,并且基本上一遍又一遍地剪切/粘贴我的访问器功能.
例如,C Struct使用a time_t,我插入访问器方法来往/来自a DateTime.另一个例子是以逗号分隔的列表,我想进入/离开Array并自动处理split/ join.
有一个更好的方法吗?
编辑:添加示例:
constant time_t = uint64;
constant FooType_t = uint16;
enum FooType <A B C>;
class Foo is repr('CStruct') is rw
{
has uint32 $.id;
has Str $.name;
has FooType_t $.type;
has time_t $.time;
method name(Str $n?) {
$!name := $n with $n;
$!name;
}
method type(FooType $t?) {
$!type = $t with $t;
FooType($!type);
}
method time(DateTime $d?) { …Run Code Online (Sandbox Code Playgroud) 这是" 如何在Perl 6中声明固定大小的本机数组? " 的后续问题.
在那个问题中讨论了如何将固定大小的数组合并到一个CStruct.在这个答案有人建议使用HAS内联CArray的CStruct.当我测试这个想法时,我遇到了一些在问题下面的评论部分无法解决的奇怪行为,所以我决定把它写成一个新问题.这是我的C测试库代码:
slib.c:
#include <stdio.h>
struct myStruct
{
int A;
int B[3];
int C;
};
void use_struct (struct myStruct *s) {
printf("sizeof(struct myStruct): %ld\n", sizeof( struct myStruct ));
printf("sizeof(struct myStruct *): %ld\n", sizeof( struct myStruct *));
printf("A = %d\n", s->A);
printf("B[0] = %d\n", s->B[0]);
printf("B[1] = %d\n", s->B[1]);
printf("B[2] = %d\n", s->B[2]);
printf("C = %d\n", s->C);
}
Run Code Online (Sandbox Code Playgroud)
要使用以下方法生成共享库:
gcc -c -fpic slib.c
gcc -shared -o …Run Code Online (Sandbox Code Playgroud) 我有一个使用NativeCall的模块,可以在Linux和macOS上运行,但不能在Windows上运行.当我尝试在Windows上使用该模块时,我遇到了很多错误,例如:
# Cannot locate symbol 'TinyTIFFReader_open' in native library 'tinytiff.dll'
Run Code Online (Sandbox Code Playgroud)
我使用cmake来解决所有三个操作系统上的C++依赖问题.在Linux和macOS上我可以cmake ..; make; sudo make install,在Windows上cmake -G "Visual Studio 15 2017 Win64" ..然后在Visual Studio中打开创建的".sln"进行编译.构建成功,所有三个操作系统都没有错误.
有没有人知道我需要做什么/更改以使我的模块在Windows上工作?
我有这个C代码:
typedef struct {
double dat[2];
} gsl_complex;
gsl_complex gsl_poly_complex_eval(const double c[], const int len, const gsl_complex z);
Run Code Online (Sandbox Code Playgroud)
C函数返回整个结构,而不仅仅是指针,因此我不能将Raku声明写为:
sub gsl_poly_complex_eval(CArray[num64] $c, int32 $len, gsl_complex $z --> gsl_complex)
is native(LIB) is export { * }
Run Code Online (Sandbox Code Playgroud)
有什么建议吗?
https://docs.perl6.org/language/nativecall
"As you may have predicted by now, a NULL pointer
is represented by the type object of the struct type."
Run Code Online (Sandbox Code Playgroud)
https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw
C++
LSTATUS RegQueryValueExW(
HKEY hKey,
LPCWSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
lpReserved
This parameter is reserved and must be NULL.
Run Code Online (Sandbox Code Playgroud)
使用“本机”,我如何满足“NULL”要求?
constant WCHAR := uint16;
constant DWORD := int32;
sub RegQueryValueExW( DWORD, WCHARS, DWORD, DWORD, DWORD is rw, DWORD is rw ) is native("Kernel32.dll") returns DWORD { * };
$RtnCode = RegQueryValueExW( $Handle, …Run Code Online (Sandbox Code Playgroud) 我正在寻找编写linspaceNumPy 的函数。
由于编译代码中的循环速度更快,因此尝试用 C 编写并从 Raku 调用。
// C code
#include <stdio.h>
#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT extern // if c++ code, requires extern "C"
#endif
DLLEXPORT void c_linspace(double start, double step, int num, double* vals) {
for (int i = 0; i < num; i++)
{
vals[i] = start;
start += step;
}
}
Run Code Online (Sandbox Code Playgroud)
// Raku code
sub c_linspace(num64, num64, int32, CArray[num64])
is native( MYDYN) { * };
sub raku_linspace($start, $end, $num, :$endpoint = …Run Code Online (Sandbox Code Playgroud) 试图与一个 C 库接口,该库采用一个带有一堆指向它在不同点调用的函数的指针的结构。
像这样:
struct callbacks {
int (*foo)(int);
int (*bar)(int);
}
int set_callbacks(callbacks *cbs);
Run Code Online (Sandbox Code Playgroud)
我可以进行回调:
sub foo-callback(int32 --> int32) {...}
sub bar-callback(int32 --> int32) {...}
Run Code Online (Sandbox Code Playgroud)
如果这样做会很酷:
class Callbacks is repr<CStruct>
{
has &.foo (int32 --> int32);
has &.bar (int32 --> int32);
}
Run Code Online (Sandbox Code Playgroud)
但事实并非如此。我正在尝试做一些事情:
class Callbacks is repr<CStruct>
{
has Pointer $.foo;
has Pointer $.bar;
}
Run Code Online (Sandbox Code Playgroud)
并将它们设置为nativecast(Pointer, &foo-callback)或一些,但我似乎无法强迫它们在那里。
除了编写一个小 C 函数来获取所有 Perl 6 函数指针并将它们插入 C 中的结构之外,还有什么方法可以做到这一点?
我正在尝试链接libzip到 Raku,它使用了一个 voidstruct或一个没有主体的结构,如下所示:
struct zip;
typedef struct zip zip_t;
Run Code Online (Sandbox Code Playgroud)
我以同样的方式在我的 Raku 程序中声明它:
class zip_t is repr('CStruct'){};
Run Code Online (Sandbox Code Playgroud)
这失败了:
Class zip_t has no attributes, which is illegal with the CStruct representation.
Run Code Online (Sandbox Code Playgroud)
我发现该错误的唯一参考是在 MyHTML中的这个未解决的问题中。这可能使它成为一种回归,但我真的不确定。任何的想法?
$ raku -v 这是基于 MoarVM 版本 2019.07.1 构建的 Rakudo 版本 2019.07.1
以下是在 Raku REPL 上完成的。我在这里做错了什么?如何为 CArray[WCHAR] 赋值?
我希望 $lpData[0] 为 0xABCD,$lpData[1] 为 0xEF12。
> use NativeCall;
Nil
> constant WCHAR := uint16;
(uint16)
> my $ValueData = 0xABCDEF12;
2882400018
> my CArray[WCHAR] $lpData;
(CArray[uint16])
> $lpData[ 0 ] = ( $ValueData +& 0xFFFF0000 ) +> 0x10;
Type check failed in assignment to $lpData; expected NativeCall::Types::CArray[uint16] but got Array ($[])
in block <unit> at <unknown file> line 1
> $lpData[ 1 …Run Code Online (Sandbox Code Playgroud)