Use C function in Swift - ios

I want to use a C function in Swift, which has the following method definition:
int startTest(char *test1, char* test2)
If I call this method from my Swift code like this
startTest("test1", "test2")
I get the following error message:
'String' is not convertible to 'UnsafeMutablePointer<Int8>'
If I change my method definition to:
int startTest(const char *test1, const char* test2)
and call that method like this:
var test1 = "test1"
var test2 = "test2"
startTest(&test1, &test2)
I get
'String' is not identical to 'Int8'
So my question is: how can I use the C function? (it is part of a library, so changing the method call could be problematic).
Thanks in advance!

In the case of
int startTest(const char *test1, const char* test2);
you can call the function from Swift simply as
let result = startTest(test1, test2)
(without the address-of operators). The Swift strings are converted automatically
to C Strings for the function call
In the case of
int startTest(char *test1, char* test2);
you need to call the function with a (variable) Int8 buffer, because the Swift
compiler must assume that the strings might be modified from the C function.
Example:
var cString1 = test1.cStringUsingEncoding(NSUTF8StringEncoding)!
var cString2 = test2.cStringUsingEncoding(NSUTF8StringEncoding)!
let result = startTest(&cString1, &cString2)

Related

Calling C function from Swift shows different results in CLion than in Xcode [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 9 months ago.
Improve this question
I am trying to call a C function from Swift , but I do not know exactly how to define variables to pass parameters. This is the function declaration:
/* Function Declarations */
extern void compute_feature_set(const double input[11025],
double M_data[], int M_size[2],
double D_data[], int D_size[2],
double DD_data[],
int DD_size[2],
double VT[10], double *mp,
double r_42[42], double *fM);
The data is an array of floats. So I tried ​​:
let s = data.compactMap{ Double($0)}
var mSize = Array<Int32>(repeating:Int32(0.0), count:2)
var dSize = Array<Int32>(repeating:Int32(0.0), count:2)
var dD_Size = Array<Int32>(repeating:Int32(0.0), count:2)
var mData = Array<Double>(repeating:0.0, count:48)
var dData = Array<Double>(repeating:0.0, count:48)
var dD_Data = Array<Double>(repeating:0.0, count:48)
var vt = Array<Double>(repeating:0.0, count:10)
var mp = Double(0.0)
var r = Array<Double>(repeating:0.0, count:42)
var fM = Double(0)
compute_feature_set(s, &cout, &mSize, &vx, &dSize, &dD_Data, &dD_Size, &vcta, &mp, &r, &fM)
When I run the code in Clion with the following function it works fine and the output matches the expected values:
static void main_compute_feature_set(void)
{
static double dv[11025];
double DD_data[48];
double D_data[48];
double M_data[48];
double r_42[42];
double VT[10];
double fM;
double mp;
int DD_size[2];
int D_size[2];
int M_size[2];
/* Initialize function 'compute_feature_set' input arguments. */
/* Initialize function input argument 'input'. */
/* Call the entry-point 'compute_feature_set'. */
argInit_11025x1_real_T(dv);
compute_feature_set(dv, M_data, M_size, D_data, D_size,
DD_data, Dd_size, VT,
&mp, r_42, &fM);
}
However, when I run my implementation in Swift, I get very different results.
You could try passing pointers of the Arrays, rather than the Arrays directly.
Using Imported C Functions in Swift | Apple Developer Documentation
Call Functions with Pointer Parameters
Whenever possible, Swift avoids giving you direct access to pointers. When importing C function parameters, however, Swift maps pointer parameters to standard library pointer types.
The following tables use Type as a placeholder type name to indicate syntax for the mappings.
For return types, variables, and arguments, the following mappings apply:
C Syntax
Swift Syntax
const Type *
UnsafePointer<Type>
Type *
UnsafeMutablePointer<Type>
double[] is pretty much equivalent to double * in this case.
Looks like the problem with your code is passing data to your function. You use compactMap to make an Array of Double and then pass the pointer of this array. But Array and Double are struct in Swift so you pass the pointer of struct with structs instead of array of double values.
To convert your data to array of bytes you should use withUnsafeBytes e.g.:
Swift:
let data = Data([0xaa, 0xbb, 0xcc, 0xdd])
data.withUnsafeBytes {
passData($0)
}
C/ObjC:
void passData(const double input[11025]) {
NSLog(#"%x", input[0]); // Prints: ddccbbaa
}

Swift: convert const char ** output parameter to String

I'm interacting with a C++ library (with the header in C) which uses const char ** as an output parameter.
After executing a method in that library, the value I need is written in that variable, for example:
CustomMethod(const char **output)
CustomMethod(&output)
// Using the `output` here
Normally, in Swift it's possible to pass just a standard Swift String as a parameter and it will be transparently transformed into the const char * (Interacting with C Pointers - Swift Blog).
For example, I already use the following construct a lot with the same library:
// C
BasicMethod(const char *input)
// Swift
let string = "test"
BasicMethod(string)
However, when it comes to working with const char **, I couldn't just pass a pointer to the Swift String, as I'd expected:
// C
CustomMethod(const char **output)
// Swift
var output: String?
CustomMethod(&output)
Getting an error:
Cannot convert value of type 'UnsafeMutablePointer<String?>' to
expected argument type 'UnsafeMutablePointer<UnsafePointer?>'
(aka 'UnsafeMutablePointer<Optional<UnsafePointer>>')
The only way I could make it work is by manipulating the pointers directly:
// C
CustomMethod(const char **output)
// Swift
var output: UnsafePointer<CChar>?
CustomMethod(&output)
let stringValue = String(cString: json)
Is there any way to use the automatic Swift string to const char ** conversion, or does it only work with const char *?
The bridged C function expects a mutable pointer to a CChar pointer, so you'll need to provide one, there's no automatic bridging here.
var characters: UnsafePointer<CChar>?
withUnsafeMutablePointer(to: &characters) {
CustomMethod($0)
}
if let characters = characters {
let receivedString = String(cString: characters)
print(receivedString)
}
Same code, but in a more FP manner:
var characters: UnsafePointer<CChar>?
withUnsafeMutablePointer(to: &characters, CustomMethod)
var receivedString = characters.map(String.init)
print(receivedString)

File operation in drivers and struct declaration

i am trying to figure out how the code behind a basic kernel driver works.
I have the following struct:
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
And my dev_open function is defined as:
static int dev_open(struct inode *, struct file *);
Now Im also familiar with the fact that the prototype for opening a device file is defined in the linux/fs.h:
http://lxr.linux.no/linux+v3.10/include/linux/fs.h#L1517
Here is the specific line from that link:
int (*open) (struct inode *, struct file *);
Now my question is what is the relationship between .open = dev_open, and int (*open) (struct inode *, struct file *);
which is defined in linux/fs.h? Is it passing the address of dev_open to the function pointer int (*open) defined in the linux/fs.h? There must be some relation or what is the point of defining the struct fops as type "file operation"?
A similar question was asked and answered here but i feel that my question was left out:
File operations in drivers
Thank you
I think this question is more about C than the Linux kernel.
Members of structure or union types cannot have function type, but they can have pointer to function type. For example, in the Linux kernel, the open member of struct file_operations needs to be declared with a pointer to function type: int (*open)(struct inode *, struct file *);. Declaring the member as int open(struct inode *, struct file *); is an error.
In this variable definition in Linux kernel code:
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
Incidentally, the above should normally have the owner member initialized like so:
.owner = THIS_MODULE,
The expressions dev_open, dev_read, dev_write and dev_release are function designators being used as assignment expressions to initialize the members of fops. A function designator is an expression that has function type. Unless it is the operand of sizeof, _Alignof, or the unary & operator, a function designator is converted to a pointer to function type. Therefore, the above definition of variable foo is exactly equivalent to:
static struct file_operations fops =
{
.open = &dev_open,
.read = &dev_read,
.write = &dev_write,
.release = &dev_release,
};
(Don't forget to also initialize .owner = THIS_MODULE,.)
There, the function designators are operands of the unary & operator and so are not converted to pointer to function types implicitly, but the & operator is converting them to pointer to function types explicitly.
After the above initialization of fops, rc = fops.open(inode, file); indirectly calls dev_open(inode, file) and assigns the return value to rc. You may sometimes see this written in an older style: rc = (*fops.open)(inode, file);. They both do the same thing. The operand of the function call operator ( ) is in fact always a pointer to a function. In the case of rc = (*fops.open)(inode, file);, fops.open has a pointer to a function type. (*fops.open) dereferences fops.open to a function type but since (*fops.open) is a function designator it is implicitly converted back to a pointer to function type before the function call. Similarly, in the direct call rc = dev_open(inode, file);, dev_open is a function designator and so has a function type, but is implicitly converted to a pointer to function type before the function call.

typedef struct from C to Swift

I'm working on a Swift app that accesses a C library.
The .h file contains a typedef struct:
typedef struct _DATA_KEY_ * CURRENT_DATA_KEY;
And there a method in another class:
-(int) initWithKey(CURRENT_DATA_KEY * key);
I need to create a CURRENT_DATA_KEY in my code. Not sure how I can achieve that in Swift.
There is some old Objective-C code that uses:
CURRENT_DATA_KEY key = NULL;
initWithKey(key)
I've tried:
let myKey = UnsafeMutablePointer<CURRENT_DATA_KEY>.allocate(capacity: 1)
But when I try to use it later as an argument in the function, I get the error:
Cannot convert value of type 'UnsafeMutablePointer<_DATA_KEY_>' (aka 'UnsafeMutablePointer(<OpaquePointer>)') to expected argument type 'UnsafeMutablePointer(<_DATA_KEY_?>!)'
Which looks like the function is expecting an optional value?
I also tried:
let myKey: CURRENT_DATA_KEY? = nil
let myKey: CURRENT_DATA_KEY = NSNull()
But those get similar type errors.
How do I create: UnsafeMutablePointer(<_DATA_KEY_?>!)
It's been a bit since I've done this but IIRC this:
typedef struct _DATA_KEY_ * CURRENT_DATA_KEY;
-(int) initWithKey(CURRENT_DATA_KEY * key);
Is actually equivalent to:
-(int) initWithKey(struct _DATA_KEY_ ** key);
So if we look up Interacting with C APIs: Pointers it falls under:
Type **
Which becomes:
AutoreleasingUnsafeMutablePointer<Type>
If you know the members of the C struct then you may be able to treat it like a Swift struct and use the synthesized init method. So if it is defined like this:
struct _DATA_KEY_ {
int foo
};
It becomes like this in Swift:
public struct _DATA_KEY_ {
var foo: Int
init()
init(foo: Int)
}
And you call the init method like:
// no parameter
let myKey = AutoreleasingUnsafeMutablePointer<_DATA_KEY_>(&_DATA_KEY_())
// parameter
let myKey = AutoreleasingUnsafeMutablePointer<_DATA_KEY_>(&_DATA_KEY_(foo: 12))
I have not tried this code but I've followed the advice in the Apple document before and it's worked out well.

Calling C function from Swift

I am trying to call a C function from Swift , but I do not know exactly how to define variables to pass parameters.
The function c is:
DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName, int * pnWidth, int * pnDecimals );
The main problem is pszFieldName, pnWidth and pnDecimals inout parameters. I tried made ​​:
var dbf:DBFHandle = DBFOpen(pszPath, "rb")
var fName:[CChar] = []
var fieldWidth:Int32 = 0
let fieldDecimals:Int32 = 0
let fieldInfo:DBFFieldType = DBFGetFieldInfo(dbf, i, fName, &fieldWidth, &fieldDecimals)
but it gives me an error
Cannot invoke 'DBFGetFieldInfo' with an argument list of type '(DBFHandle, Int32, [CChar], inout Int32, inout Int32)'
Expected an argument list of type '(DBFHandle, Int32, UnsafeMutablePointer<Int8>, UnsafeMutablePointer<Int32>, UnsafeMutablePointer<Int32>)'
Any ideas?
UnsafeMutablePointer<Int8>, UnsafeMutablePointer<Int32>, UnsafeMutablePointer<Int32>
You need to convert your variables to the appropriate types required by the method signature.
C Syntax:
const Type *
Type *
Swift Syntax:
UnsafePointer
UnsafeMutablePointer
This is covered by Apple in their Using Swift with Cocoa and Objective-C reference located here.
C Syntax -----> Swift Syntax
const Type * -----> UnsafePointer
Type * -----> UnsafeMutablePointer
The number of input and the types should be the same
To create an UnsafeMutablePointer<Int8> from a string use:
String(count: 10, repeatedValue: Character("\0")).withCString( { cString in
println()
// Call your function here with cString
})

Resources