How do I convert this C (array) type:
char my_buf[BUF_SIZE];
to this Go (array) type:
type buffer [C.BUF_SIZE]byte
? Trying to do an interface conversion gives me this error:
cannot convert (*_Cvar_my_buf) (type [1024]C.char) to type [1024]byte
The easiest and safest way is to copy it to a slice, not specifically to [1024]byte
mySlice := C.GoBytes(unsafe.Pointer(&C.my_buff), C.BUFF_SIZE)
To use the memory directly without a copy, you can "cast" it through an unsafe.Pointer.
mySlice := (*[1 << 30]byte)(unsafe.Pointer(&C.my_buf))[:int(C.BUFF_SIZE):int(C.BUFF_SIZE)]
// or for an array if BUFF_SIZE is a constant
myArray := *(*[C.BUFF_SIZE]byte)(unsafe.Pointer(&C.my_buf))
To create a Go slice with the contents of C.my_buf:
arr := C.GoBytes(unsafe.Pointer(&C.my_buf), C.BUF_SIZE)
To create a Go array...
var arr [C.BUF_SIZE]byte
copy(arr[:], C.GoBytes(unsafe.Pointer(&C.my_buf), C.BUF_SIZE))
Related
I have this C code:
uint8_t *data[BUF_SIZE];
data = ...;
// extern void goReadData(uint8_t *data, int bufferSize);
goReadData(data, BUF_SIZE)
And in the GO Code I'm trying to use the data pointer as a GO array or slice, I want to retrieve an []uint8 from the *C.uint8_t. I know the size of the data
//export goReadData
func goReadData(data *C.uint8_t, bufferSize C.int) {
fmt.Printf("Data type %v\n", reflect.TypeOf(data))
// print 1: Data type *main._Ctype_uchar
// Solution 1: GoBytes
// works but really slow (memory copy I think)
goBytes := C.GoBytes(unsafe.Pointer(data), bufferSize)
fmt.Printf("goBytes type %v\n", reflect.TypeOf(goBytes))
// print 2: goBytes type []uint8
// Solution 2: direct pointer
// Really fast, but wrong type at the end
// unsafe.Pointer to the C array
unsafePtr := unsafe.Pointer(data)
// convert unsafePtr to a pointer of the type *[1 << 30]C.uint8_t
arrayPtr := (*[1 << 30]C.uint8_t)(unsafePtr)
// slice the array into a Go slice, with the same backing array
// as data, making sure to specify the capacity as well as
// the length.
length := int(bufferSize)
slice := arrayPtr[0:length:length]
fmt.Printf("Direct slice type %v\n", reflect.TypeOf(slice))
//Print 3: Direct type []main._Ctype_uchar
}
How could I do to recover an []uint8 instead of []main._Ctype_uchar with the second solution? Or do you have another solution to do that without a bytes copy?
Sorry guys, I found my own mistake:
// convert unsafePtr to a pointer of the type *[1 << 30]C.uint8_t
arrayPtr := (*[1 << 30]C.uint8_t)(unsafePtr)
==> to
// convert unsafePtr to a pointer of the type *[1 << 30]uint8
arrayPtr := (*[1 << 30]uint8)(unsafePtr)
Problem solved!
Thanks ;)
I need to call a function expecting an array of Integer, but I have my values in a variable of type Variant, containing the array.
Do I really have to copy the values in a loop? I couldn't find a better way that works.
The same variant can also hold a single Integer instead of the array, so I created a helper function allowing both (checking with VarIsArray). It works, but it is just lengthy and not nice :)
type
TIntegerArray = array of Integer;
function VarToArrayInt(const V: Variant): TIntegerArray;
var
I: Integer;
begin
if VarIsArray(V) then begin
SetLength(Result, VarArrayHighBound(V, 1) + 1);
for I:= 0 to High(Result) do Result[I]:= V[I];
end else begin
SetLength(Result, 1);
Result[0]:= V;
end;
end;
I'm using Delphi 10.2.2 and the function to be called cannot be changed and looks like this:
function Work(Otherparameters; const AParams: array of Integer): Boolean;
If the function takes an array of Integer as a separate type, eg:
type
TIntegerArray = array of Integer;
function DoIt(const Values: TIntegerArray): ReturnType;
Then the function takes a Dynamic Array as input. You can assign/pass a Variant holding an array to a Dynamic Array variable/parameter. The compiler is smart enough to call the RTL's VarToDynArray() function to allocate a new Dynamic Array that has a copy of the Variant's array elements. There is no way to pass a Variant holding an array to a Dynamic Array without making a copy of the array data.
However, if the function takes an array of Integer directly in its parameter list instead, eg:
function DoIt(const Values: array of Integer): ReturnType;
Then it takes an Open Array as input:
an Delphi function that has an open array parameter can be called by explicitly passing two parameters:
A pointer to the first element of the array
A count, which is the value of the last index (that is, the size/number of array elements, minus one)"
You can't pass a Variant (whether it holds an array or not) directly to an Open Array parameter. The compiler is not smart enough to extract the array pointer and element count and pass them to the Open Array parameter. However, you can do it manually with a little typecast trickery, eg:
function DoIt(const Values: array of Integer): ReturnType;
...
type
TOpenArrayFunc = function(const Values: PInteger; ValuesHigh: Integer): ReturnType;
var
V: Variant;
Count: Integer;
P: PInteger;
begin
...
V := ...;
Count := VarArrayHighBound(V, 1) - VarArrayLowBound(V, 1) + 1;
P := VarArrayLock(V);
try
TOpenArrayFunc(#DoIt)(P, Count-1);
finally
VarArrayUnlock(V);
end;
...
end;
This passes the Variant's array directly to the function without making any copies of the array elements at all.
Fortunately there is no need for a loop, at least when the array is 0-based.
If the called function would expect a dynamic array, you could just pass the Variant as it is. You can also directly assign it to a dynamic array variable.
In your case it is an open array parameter, and that needs casting in this case.
Here is some demonstration of what is possible and how, including a nice and short helper function allowing both arrays and single values.
program Test;
uses Variants;
procedure PrintOpenArray(const Arr: array of Integer); {open array parameter}
var
I: Integer;
begin
for I in Arr do Writeln(I);
end;
procedure PrintDynamicArray(const Arr: TArray<Integer>); {dynamic array param}
begin
PrintOpenArray(Arr);
end;
function VarToArrayInt(const V: Variant): TArray<Integer>;
begin
if VarIsArray(V) then Result:= V else Result:= [V];
{[V] works only in XE7 and up. You can use TArray<Integer>.Create(V) instead}
end;
type {dynamic integer array, but only compatible to this type}
TIntegerArray = array of Integer;
var
V: Variant;
A: TArray<Integer>; {dynamic array, compatible to any other TArray<Integer>}
begin {all the following only works with 0-based arrays!}
V:= VarArrayCreate([0, 2], varInteger);
V[0]:= 1;
V[1]:= 2;
V[2]:= 3;
A:= V; {Variant can just be assigned to dynamic array if it contains an array}
PrintOpenArray(A);
PrintDynamicArray(V); {works directly without casting}
PrintOpenArray(TArray<Integer>(V)); {not possible without casting}
PrintOpenArray(TIntegerArray(V));
PrintOpenArray(VarToArrayInt(V));
V:= 4; {demonstration of helper function to allow arrays and single values}
PrintOpenArray(VarToArrayInt(V));
PrintDynamicArray(VarToArrayInt(V));
Readln;
end.
I have a C file with an array of type const char *, lets call it myStringArray[], something like:
const char *myStringArray[] = {
"NAME_OF_FIRST_THING",
"NAME_OF_SECOND_THING",
"NAME_OF_THIRD_THING"}
I need Go to index into that C array, using cgo, and convert an array entry into a Go string. The following code compiles but does not work correctly; you can see from the output that follows, it is indexing along the strings rather than up the array:
myGoString := C.GoString((*C.char) (unsafe.Pointer(uintptr(unsafe.Pointer(C.myStringArray)) + uintptr(index) * unsafe.Sizeof(C.myStringArray))))
...result being this:
NAME_OF_FIRST_THING
FIRST_THING
ING
FYI, the purpose of this is to decode on a server a log file that was created on an embedded platform running C, hence the need to re-use the same logging index files.
I've been stabbing at this randomly for a few hours now without success. Can anyone correct my construction, or provide an alternative?
While you could do the pointer arithmetic yourself, it's safer and more convenient to convert the C array into a Go slice first.
arraySize := 3
cStrings := (*[1 << 30]*C.char)(unsafe.Pointer(&C.myStringArray))[:arraySize:arraySize]
for _, cString := range cStrings {
fmt.Println(C.GoString(cString))
}
// prints:
// NAME_OF_FIRST_THING
// NAME_OF_SECOND_THING
// NAME_OF_THIRD_THING
Relevant cgo wiki entry: https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
I have an array of bytes and another array of array of bytes.
type
TByteArray = array of byte;
TArraykearray = array of array of byte;
function TFRTConnection1.GetBytes(value: integer): TBytearray;
begin
SetLength(Result, SizeOf(value));
Move(value, Result[0], SizeOf(value));
end;
Function TFRTConnection1.addco(point: TPoint) : Tarraykearray;
var
result1 : Tarraykearray;
begin
setLength(Result1,10);
Result1[0] := getBytes(1);
Result1[1] := 1;
....
Result := result1;
end;
When i use Result1[0] := getBytes(1); i get incompatible types error.
I do not want to make TArraykearray as array of Tbytearray because that is an array of array on the server side of the application for which I do not have access to.
Is there another possibility?
You cannot assign a TByteArray to an array of byte, the compiler treats them as separate types even though internally they are compatible. You need to change TArraykearray to use TByteArray instead:
type
TByteArray = array of byte;
TArraykearray = array of TByteArray;
Or else you will have to use a type-cast when assigning the array:
Function TFRTConnection1.addco(point: TPoint) : Tarraykearray;
type
PByteArray = ^TByteArray;
var
Result1 : TArraykearray;
begin
SetLength(Result1,10);
PByteArray(#Result1[0])^ := getBytes(1);
....
end;
BTW: Result1[1] := 1; will not compile either, as you cannot assign a single integer to an array.
I would like to write a program that receive a array (of string, int, or whatever) and create another array of the same type contain only the first element.
For example:
for a array of strings arr := []string("hello", "world")
my output would be arr2 := []string(arr[0]);
I can't use the copy function because to do that, i would have to create(make) a new slice for it. And in this case, i still have to discover which type the first array is (string, int, bool, and so on...)
Maybe I could use the reflect.TypeOf() but i would still not know how to use that information to create the same type of slice or array.
i'm not considering to use conditionals for that.
For example:
if reflect.TypeOf(arr) == []int {
arr := []int(arr[0])
} else if reflect.TypeOf(arr) == []string
arr := []string(arr[0])
} ...
I would be glad get a help on there.
Thanks in advance.
You could just subslice it in place:
s2 := s1[0:1]
But if you really need to create a new slice, you can do it like this:
func f(s interface{}) interface{} {
v := reflect.ValueOf(s)
t := v.Type()
res := reflect.MakeSlice(t, 1, 1)
res.Index(0).Set(v.Index(0))
return res.Interface()
}
Playground: http://play.golang.org/p/w1N3pgvAwr.