96273


※ 小生、C言語には疎く根本的なことを理解していない可能性がありますが、質問させていただきたく。

Ruby の Fiddle を使って構造体を引数に取る関数を定義したいのですが以下のコードだとエラーが出ます。何が間違っているのでしょうか？

[code]

    module MyDll
        require 'fiddle'
        require 'fiddle/import'
        require 'fiddle/types'
        
        extend Fiddle::Importer
        dlload %q(C:\dev\source\repos\Dll1\x64\Debug\Dll1.dll)
        include Fiddle::Win32Types
    
        Struct1 = struct([
            'short a',
            'short b',
        ])
    
        extern 'int add(Struct1)'
    end
    
    struct1 = MyDll::Struct1.malloc
    struct1.a = 1
    struct1.b = 2
    
    p MyDll.add(struct1)
    
[/code]

実行したときのエラーは以下の通りです

[code]

    C:/Ruby32-x64/lib/ruby/3.2.0/fiddle/cparser.rb:247:in `parse_ctype': unknown type: Struct1 (Fiddle::DLError)
            from C:/Ruby32-x64/lib/ruby/3.2.0/fiddle/cparser.rb:117:in `block in parse_signature'
            from C:/Ruby32-x64/lib/ruby/3.2.0/fiddle/cparser.rb:117:in `collect'
            from C:/Ruby32-x64/lib/ruby/3.2.0/fiddle/cparser.rb:117:in `parse_signature'
            from C:/Ruby32-x64/lib/ruby/3.2.0/fiddle/import.rb:168:in `extern'
            from ./fiddle.rb:15:in `<module:MyDll>'
            from ./fiddle.rb:1:in `<main>'
    
[/code]

C側のコードは以下の通りです。

[code]

    #include "pch.h"
    #include "stdio.h"
    
    typedef struct _Struct1 {
        short a;
        short b;
    } Struct1;
    
    extern "C" {
        __declspec(dllexport) int __stdcall add(Struct1 s);
        __declspec(dllexport) int __stdcall add1(Struct1 *s);
    }
    
    int add(Struct1 s) {
        return s.a + s.b;
    }
    
    int add1(Struct1 *s) {
        return s->a + s->b;
    }
    
[/code]

ruby のバージョンは `ruby 3.2.0 (2022-12-25 revision a528908271) [x64-mingw-ucrt]`
でした。

Ruby・Cのコード両方のaddの引数を `Struct1` から `Struct1*`
に変更すると期待した動作になりますが、ポインタを渡すことが必須なのでしょうか？


CC BY-SA 4.0
2023-09-18T12:37:49.070
96253
2023-09-20T03:26:54.770
18863
question
ruby
Fiddleで構造体を関数に渡す方法


[ruby](/questions/tagged/ruby "'ruby' のタグが付いた質問を表示") のコード

[code]

    struct1 = MyDll::Struct1.malloc
    struct1.a = 1
    struct1.b = 2
    
[/code]

を [c](/questions/tagged/c "'c' のタグが付いた質問を表示") に翻訳するなら

[code]

    Struct1* struct1 = malloc(sizeof(Struct1));
    struct1->a = 1
    struct1->b = 2
    
[/code]

相当です。だからその `struct1` を素直に [c](/questions/tagged/c "'c' のタグが付いた質問を表示") に渡すのであれば
`int add1(Struct1* s) {...}` で受けろ、ということになります。  
# どうしても `int add(Struct1 s)` を呼びたいって場合にどうすればよいかは未調査


CC BY-SA 4.0
2023-09-20T03:26:54.770
96273
2023-09-20T03:26:54.770
8589
96253
answer