Ccall works on global scope but not within function

,

Thanks, I did make the mistake with pointer before, but I fixed that after I started using Clang.jl to generate the bindings.

Here’s a slightly involved example that supposedly reproduces how this library works. I’m not sure I reproduced all the bugs, but it does illustrate one of the issues I’m having. I’m using this way to transform NTuple{N, UInt8} to strings, and that fails when I move the code to within a function. There seems to be some gotcha related to references. What’s the proper way to encapsulate that code, creating a handy getstr or something similar?

Here’s my C code

#include<stdint.h>
#include<stdio.h>

struct MyStruct {
  char name[16];
  uint8_t ipaddress[4];
  double xyz;
};


int writedata(struct MyStruct * buffer, int * buffersize) {
  *buffersize = *buffersize >> 1;
  for (int i = 0 ; i< *buffersize; i++) {
    int j = 0;
    for (; j<3; j++)
      buffer[i].name[j] = 'a' + j + (j+1)*i;
    buffer[i].name[j] = 0;
    buffer[i].ipaddress[0] = 192;
    buffer[i].ipaddress[1] = 168;
    buffer[i].ipaddress[2] = 0;
    buffer[i].ipaddress[3] = 128 + i;
    buffer[i].xyz = i*i*3.1415;
  }
  return (*buffersize > 0) ? 0 : 1;
}

int main(int argc, char** argv) {
  struct MyStruct mydata[8];
  int buffersize = 8;
  writedata(mydata, &buffersize);
  for (int i; i < buffersize; i++) {
    printf("%s - %d.%d.%d.%d - %f\n",
	   mydata[i].name,
	   mydata[i].ipaddress[0], mydata[i].ipaddress[1], mydata[i].ipaddress[2], mydata[i].ipaddress[3],
	   mydata[i].xyz);
  }
}

/* gcc testapi.c -o testapi.so -shared -fPIC */

And the Julia code

struct MyStruct
    name ::NTuple{16, UInt8}
    ipaddress ::NTuple{4, UInt8}
    xyz ::Float64
end

# getstr(x) = unsafe_string(Ptr{UInt8}(pointer_from_objref(Ref(x))))
getstr(x) = unsafe_string(Ptr{UInt8}(pointer_from_objref(x)))
# getstr(x) = Ptr{UInt8}(pointer_from_objref(x))
# getstr(x) = x

function api_writedata(buffer, buffersize)
    ccall(
        (:writedata, "testapi.so"),
        Cint,
        (Ptr{MyStruct}, Ptr{UInt32}),
        buffer, buffersize
    )
end 

mydata = Vector{MyStruct}(undef, 8)
buffersize = Ref(0x00000008)

api_writedata(mydata, buffersize)
for data in mydata[1:buffersize[]]
    # println("$(data.name) - $(join(data.ipaddress,'.')) - $(data.xyz)")
    println("$(getstr(Ref(data.name))) - $(join(data.ipaddress,'.')) - $(data.xyz)")
end
println("***")

function process()
    mydata = Vector{MyStruct}(undef, 8)
    buffersize = Ref(0x00000008)

    api_writedata(mydata, buffersize)
    for data in mydata[1:buffersize[]]
        # println("$(data.name) - $(join(data.ipaddress,'.')) - $(data.xyz)")
        println("$(getstr(Ref(data.name))) - $(join(data.ipaddress,'.')) - $(data.xyz)")
    end
    
end

process()

The resulting output:

abc - 192.168.0.128 - 0.0
bdf - 192.168.0.129 - 3.1415
cfi - 192.168.0.130 - 12.566
dhl - 192.168.0.131 - 28.273500000000002
***
 - 192.168.0.128 - 0.0
 - 192.168.0.129 - 3.1415
 - 192.168.0.130 - 12.566
 - 192.168.0.131 - 28.273500000000002