In Swift why is char * becoming UnsafePointer<Int8>? - c

I have added files containing Objective-C classes from another project into my Swift project. In one of these Obj-C classes, there is a data member called "decodedBuffer" of type char *. I'm not well-versed in C, but I thought that a char pointer was C's way of representing a String. When I try to get this data member while in my Swift code, for instance by writing the following line
myObjCClass.decodedBuffer = "a new value"
I get an error saying decodedBuffer is of type UnsafePointer<Int8>. So I have two questions:
Why is a char * a UnsafePointer<Int8> in Swift? If anything I would expect it to be UnsafePointer<CChar>.
How do I work with this value in Swift? The library I'm using is kind of a black box, as well as being completely in Objective-C, and so I'm not 100% how the data I pass by assigning a value to decodedBuffer will be processed. Any tips on how to interface with C objects in Swift? Yes I have read the "Interacting With C API's" portion of the Swift docs, but I would like some user-gained wisdom on interfacing with C API's if possible.

Just like Swift, in C you can declare mutable (var) or immutable (let) variables.
Your C library is passing you an UnsafePointer<Int8> = an immutable value.
One way to get your solution is to access the C code you can change it a mutable value. Then you can deal with the: UnsafeMutablePointer = a mutable value.
Your second question about why is it represented as an < Int8 > type gets to the heart of pointers in C. You don't pass around strings of data into different memory locations. You pass the pointer. The pointer points to the memory location of the first character of the char array (the string) held within memory. Much more efficient.
A Swift example to show the int value of a C pointer:
let greeting: String = "Hello World."
let greetingPointer = strdup(greeting) // UnsafeMutablePointer<Int8>?
print("I am your \(greetingPointer). I point to memory location of Greeting.")

Related

Initialize flexible array C struct member from Go

I am trying to initialize a struct of C array in go side.
I am new to cgo. Still trying to understand the use case.
test.h
typedef struct reply {
char *name;
reply_cb callback_fn;
} reply_t;
typedef struct common {
char *name;
int count;
reply_t reply[];
} common_t;
int
init_s (common_t *service);
test.go
name := C.CString("ABCD")
defer C.free(unsafe.Pointer(name))
num := C.int(3)
r := [3]C.reply_t{{C.CString("AB"), (C.s_cb)(unsafe.Pointer(C.g_cb))},
{C.CString("BC"), (C.s_cb)(unsafe.Pointer(C.g_cb))},
{C.CString("CD"), (C.s_cb)(unsafe.Pointer(C.g_cb))}}
g := C.common_t{
name: name,
count: num,
reply : r,
}
rc := C.init_s(&g)
I am getting error on "reply: r" unknown field 'r' in struct literal of type
Any help will be appreciated. The goal is initialize and then use it values in C init_s for processing.
You cannot use a flexible array field from Go: https://go-review.googlesource.com/c/go/+/12864/.
I think the reasonong is simple: this wart of C normally requires you to perform a trick of allocating a properly-aligned memory buffer long enough to accomodate for the sizeof(struct_type) itself at the beginning of that buffer plus sizeof(array_member[0]) * array_element_count bytes. This does not map to Go's type system because in it, structs have fixed size known at compile time. If Go would not hide reply from the definition, it would refer to a zero-length field you cannot do anything useful with anyway—see #20275.
Don't be deceived by code examples where a flexible array member field is initialized with a literal: as torek pointed out, it's a GCC extension, but what is more important, it requires work on part of the compiler—that is, it analyzes the literal, understands the context it appeared in and generates a code which allocates large enough memory block to accomodate both the struct and all the members of the flexible array.
The initialization of the array in your Go code may look superficially similar but it has an important difference: it allocates a separate array which has nothing to do with the memory block of the struct it's supposed to be "put into".
What's more Go's array are different beasts than C's: in C, arrays are pointers in disguise, in Go, arrays are first-class citizens and when you assign an array or pass it to a function call, the whole array is copied by value—as opposed to "decaying into a pointer"—in C's terms.
So even if the Go compiler would not hide the reply field, assignment to it would fail.
I think you cannot directly use values of this type from Go without additional helper code written in C. For instance, to initialize values of common_t, you would write a C helper which would first allocate a memory buffer long enough and then expose to the Go code a pair of pointers: to the beginning of the buffer (of type *C.common_t), and to the first element of the array—as *C.reply_t.
If this C code is the code you own, I'd recommend to just get rid of the flexible array and maintain a pointer to a "normal" array in the reply field.
Yes, this would mean extra pointer chasing for the CPU but it will be simpler to interoperate with Go.

Modifying swift [CChar] arrays in C functions without returning value

I started learning C and wanted to try some of the Swift-C interoperability.
I have a small C function which reads me a file and concatenates some useful letters into a char* variable. After some testing, I cannot find a way to pass my obtained char* data back to swift. I have written a small dummy code to illustrate what I am trying to achieve.
var letters: [CChar] = []
functionWithArray(&letters)
print("Back in swift: \(letters)")
And the C function is:
void functionWithArray(char* letters) {
int arrayLenght = 5;
int testLenght = 10; // Expand array to this value (testing)
int currentArrayPosition = 0; //Keep track of the assigned values
letters = malloc(sizeof(char)*arrayLenght);
while (currentArrayPosition < testLenght) {
if (currentArrayPosition == arrayLenght) {
arrayLenght++;
letters = realloc(letters, sizeof(char)*arrayLenght);
}
letters[currentArrayPosition] = *"A";
++currentArrayPosition;
}
printf("End of C function: %s\n", letters);
}
I get this as an output:
End of C function: AAAAAAAAAA
Back in swift: []
Program ended with exit code: 0
As you can see, inside the C function I've got the desired result, but back in swift I could not find a way to obtain the modified array. I do not return letters directly with the function because I need to return more values from that function. I'm new to C so please be kind.
There are two main issues with your approach here — one in C and one in Swift:
In C, function parameters are passed by value, and are effectively mutable local variables. That means that when functionWithArray receives char *letters, letters is a local variable containing a pointer value to the buffer of letters in memory. Importantly, that means that letters is assignable, but not in the way that you think:
letters = malloc(sizeof(char)*arrayLenght);
allocates an entirely new buffer through malloc, and assigns the newly-created pointer value to your local letters variable. Before the assignment, letters is a pointer to the buffer you were getting from Swift; after, to an unrelated buffer in memory. These two buffers are completely unrelated to one another, and because letters is just a local variable, this assignment is not propagaged in any way outside of the function.
Note that this is just a rule of C: as you learn more C, you'll likely discover that in order to assign a variable from inside of a function to outside of a function, you need to wrap the variable in another layer of pointers and write through that pointer (e.g., you would need to receive char **letters and assign *letters = malloc(...) to have any effect on a variable being passed in — and the variable couldn't be passed in directly, but rather, its address would need to be passed in).
However, you can't generally make use of this fact because,
The implicit conversion of an Array<T> to an UnsafeMutablePointer<T> (e.g. [CChar] → UnsafeMutablePointer<CChar> in Swift == char * in C) does not allow you to assign an entirely new buffer to the array instance. You can write into the contents of the buffer by writing to pointer values, but you cannot allocate a new block of memory and reassign the contents of the array to that new block
Instead, you'll need to either:
Have functionWithArray return an entirely new array and length from C — you mention this isn't possible for functionWithArray specifically because of the other values it needs to return, but theoretically you can also create a C struct which wraps up all of the return values together and return one of those instead
Rewrite functionWithArray to receive an array and a length, and pre-reserve enough space in the array up-front to fill it appropriately:
var letters: [CChar] = []
letters.reserveCapacity(/* however much you need */)
functionWithArray(&letters, letters.capacity)
In functionWithArray, don't reassign letters, but instead fill it up to the capacity given to you with results. Of course, this will only work if you know in Swift ahead of time how much space functionWithArray will need, which you might not
Alternatively, you can also use Array.init(unsafeUninitializedCapacity:initializingWith:) to combine these operations by having Array preallocate some space, and you can pass in the inout UnsafeMutableBufferPointer<CChar> to C where you can allocate memory if you need to and assign to the buffer pointer, then write out to the inout Int how many array elements you allocated and initialized. This does also require a capacity, though, and is a more complicated solution
Of these two approaches, if functionWithArray really does need to dynamically reallocate memory and grow the buffer, then (1) is likely going to be easier.

Array of fixed length strings in c

I'd like to have an array of fixed length strings in c in the form of a pointer so I can dynamically allocate the memory for it.
I can see plenty of reference to arrays of pointers to string, but not to what I want to achieve.
What I want is to be able to declare a pointer to char[MAX_STRING_LENGTH] so I can then dynamically allocate a contiguous block of memory for all the strings:
char *(names[MAX_STRING_LENGTH]); // This won't work
names = (some cast)malloc(NUM_STRINGS * MAX_STRING_LENGTH);
And then access the array of strings:
strcpy(name, names[stringIndex]);
How do I declare the variable and cast the pointer from malloc?
You declare names as an array of pointers, not a pointer to arrays. That would be
char (*names)[MAX_STRING_LENGTH]; // Names is a pointer to an array of char
Now you can allocate memory for the pointer:
// Allocate memory for NUM_STRINGS arrays and assign the pointer to names
names = malloc(NUM_STRINGS * sizeof *names);
You want a pointer to array MAX_LENGTH of char Using cdecl (note that cdecl doesn't understand things like MAX_LENGTH so we use a number here instead):
% cdecl
Type `help' or `?' for help
cdecl> declare names as pointer to array 256 of char;
char (*names)[256]
we get that the proper declaration is
char (*names)[MAX_LENGTH];
However this still isn't very useful, because reallocation would be very costly because it possibly could have to move each and every string to a new location. So I suggest that you'd still use a pointer to pointer to char.
Someprogrammerdude already provided the solution.
Generally, since C/C++ types can become somewhat tricky, you can utilize any half-decent IDE to look up correct type definitions.
This trick relies on the C++11 auto keyword, which determines a variable type from its initializer. The resulting type can still be used in other C/C++ versions and is not restricted to C++11.
In your case, specify a type that you know and that can be transformed into the type you want:
char names[10][10];
Then assign an auto variable with the desired type:
auto names2 = &names[0];
Inspect the actual type of names2 and use it. For example, in Visual Studio, just hover the mouse over names2 to see the type. Most IDEs will display the type by hovering over either the auto keyword or the defined variable.
For the example, hovering would reveal the type char (*names2)[10].
You need to understand the concept of Pointer Arrays.Refer the book "The C programming Language" By Dennis M. Ritchie & Kernighan. Specially the pointer and array part.There are some amazing stuffs to read. Probably you will get a more deeper concept of pointers and arrays after reading and solving some problems given in the book.

Byte array from C++/CLI to C

I have a function in visual c++ something like this:
DoSomething(IVector<unsigned char>^ inputBytes)
which is used to pass a byte array. And in this method i need to access a method of C class which accepts the byte array paramter(inputBytes). I have placed method like this in C class
void TestFunction(unsigned char* testdata[])
but it throws an error.What is the syntax of the byte array in c. How to pass this bytearray from c++ to c. Can anyone please help me to find the solution.
You declared array of pointers to char in your C function. I don't know C++/CLI, so not sure at all, but correct is one of these, I think:
void TestFunction(unsigned char* testdata)
or for many purposes exactly equal (subtle differences only):
void TestFunction(unsigned char testdata[])
First is pointer to char, or some number of chars, such as C style string. Second is array of some number of chars, which in C is almost same as pointer to char.
Most likely you need to add an int parameter, telling number of bytes, as C arrays do not know their own size (they are basically glorified pointers, as I said above), unless you can know the size some other way (like C strings end at first 0 byte).

How many asterisks should I use when declaring a pointer to an array of C-strings?

I am having a VB application request a list of users from a C DLL:
VB will ask the DLL how many users there are, and then initialize an array to the appropriate size.
VB will then pass its array by reference to a DLL function, which will fill it with usernames.
I started writing the C function like this: foo(char **bar); which would be treated as an array of strings. But then I realized, I'm going to make each item in the array point to a different C-string (the char *username in the struct userlist linked list) rather than modify the data already being pointed to. The array of arrays is being passed by value: a copy of a list of addresses, so the addresses point to the original data, but modifying the addresses in that copy won't change the list of addresses of the caller (I think, anyways). So, should I be declaring it foo(char ***bar);? This would be a pointer to the array of strings, so that if I change the strings that array is pointing to, it will modify the array of strings the caller (VB) is using....right?
This is my usage so far (haven't tested it yet... I'm still just coding the DLL as of yet, there's no VB front-end to call it thus far)
EXPORT void __stdcall update_userlist(char ***ulist){
int i = 0;
userlist *cur_user = userlist_head; //pointer to first item in linked list
for(; i < usercount_; ++i){
*ulist[i] = cur_user->username;
cur_user = cur_user->next;
}
}
In general it's not simple to do what you're asking, because VB just doesn't understand C-style ASCIIZ strings and arrays.
If your DLL is not expecting a VB SafeArray of BSTR, you're going to have some difficulty populating it.
It would be simple to have VB pass in an array of Long (C int) by reference to the first element, and you could fill that with the pointers to individual strings. The VB side could copy them to VB strings. But in that case, who disposes of the C strings, and when?
If you create the VB array and fill it with pre-sized strings, you'll still have to deal with a SafeArray on the C side, because you can't pass a single VB string array element by reference and expect to find the remaining strings contiguous to it in memory.
The best, safest method is to have your DLL create a SafeArray of so-called 'Ansi BSTR', and declare the function in VB as returning an array of strings. Then you don't need two calls, because the array bounds will tell the whole story.
===== edit =====
When VB passes a string array to a Declared function it does some voodoo behind the scenes. It first converts all the strings from Unicode to a bastard form commonly known as 'Ansi BSTR'. To C, these look like and can be treated as ASCIIZ or LPSTR except that you can't create or lengthen them in the normal C way, you can only fill them in. On the C side, the passed array looks like ppSA (SAFEARRAY**). The Ansi BSTR are a series of pointers referenced by the pData member of the SafeArray.
You absolutely cannot pass a single string from the array (as char*) and expect to find the rest of the strings contiguous to it in memory. You have to pass the array itself and manipulate it using the SafeArray API (or knowledge of the SA structure).
That's why the best option overall is to do all of this directly in the DLL. Create the array using SafeArrayCreate, then create Ansi BSTRs using SysAllocStringByteLen and place those strings (which are BSTR, so a 4-byte pointer) into the array slots. On return, VB does its voodoo and converts the strings to Unicode for you.
In VB your function would be Declared as returning a String().
two asterixes is the way to go.
char* // is a pointer to a char
char** // is a pointer to a char pointer
char*** // is a pointer to a pointer to a char pointer - e.g. multi-dimensional array (err...)
I've confused myself :)
So let me get this straight. Your function fills in an array of strings from data contained in a linked list ?
If you know the size of the list beforehand, you can just pass a char **, but if you do not know the size and need to be able to grow the list, you will need a char ***.
From looking at your code, you seem to already know the length, so you just need to allocate an array of the correct length before you call the function. Here is an example:
void update_userlist(char **ulist)
{
int i = 0;
userlist *cur_user = userlist_head;
for(; i < usercount_; ++i)
{
ulist[i] = cur_user->username; // I am assuming that username is a char *
cur_user = cur_user->next;
}
}
// This sets up the array and calls the function.
char **mylist = malloc(sizeof(char*) * usercount_);
update_userlist(mylist);
Update: Here is the difference between the various levels of pointers:
void func1(char *data)
This passes a copy of a pointer to a C string. If you change the pointer to point to a different string, the calling function will still point to the original string.
void func2(char **data)
This passes a copy of a pointer to an array of pointers to C strings. You can replace the pointer to any string in the array and the calling function's array will be changed because it has not made a copy of the array, it only points to the caller's array.
void func3(char ***data)
This passes a pointer to a pointer to an array of pointers to C strings. With this, you can completely replace the entire array. You would only need this level of indirection if you need to grow the array since C arrays cannot be re-sized.

Resources