Calling C function from Swift - ios

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
})

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)

Cannot convert value of type 'Int' to expected argument type 'UInt32'

I am trying to generate a random number in Swift:
var amountOfQuestions = 2
var randomNumber = Int(arc4random_uniform(amountOfQuestions - 1)) + 1
but this results in the error:
Cannot convert value of type 'Int' to expected argument type 'UInt32'
What is the problem? Any ideas on what I can do to fix this error?
Declare amountOfQuestions as a UInt32:
var amountOfQuestions: UInt32 = 2
PS: If you want to be grammatically correct it's number of questions.
First thing:
The method "arc4random_uniform" expects an argument of type UInt32, so when you put that subtraction there, it converted the '1' you wrote to UInt32.
Second thing: In swift you can't subtract a UInt32 (the '1' in your formula) from an Int (in this case 'amountOfQuestions').
To solve it all, you'll have to consider changing the declaration of 'amountOfQuestions' to:
var amountOfQuestions = UInt32(2)
That should do the trick :)
Make your amountOfQuestions variable an UInt32 rather than an Int inferred by the compiler.
var amountOfQuestions: UInt32 = 2
// ...
var randomNumber = Int(arc4random_uniform(amountOfQuestions - 1)) + 1
arc4random_uniform requires a UInt32.
From the Darwin docs:
arc4random_uniform(u_int32_t upper_bound);

Use C function in Swift

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)

Does Swift support implicit conversion?

For example, I have the following code:
let numberOfBlocks = 3
let blockWidth = SKSpriteNode(imageNamed: "image.png").size.width
let padding = 20.0
let offsetX : Float = (self.frame.size.width - (blockWidth * numberOfBlocks + padding * (numberOfBlocks-1))) / 2
I got the error:
'Double' is not convertible to 'UInt8'
Is there a way to implicitly convert the data type (maybe only for primitive data type)?
Edit:
I know how to do the explicit conversion by using constructor of particular type as Iducool suggested. But it's not a big help to my question because we even don't know where to add the conversions. I simplified my expression in playground:
The problem is in "padding" variable, the error message is
'Double' is not convertible to 'UInt8'.
So I did the conversion:
Then the problem is in "blockWidth" variable now.
I added the conversion again:
And error message is:
Type 'UInt8' does not conform to protocol 'FloatLiteralCovertible'
The final working expression is:
Is it simple and swift? I don't think so.
There is no implicitly cast in Swift.
Easy way of conversion in swift is using constructor of particular type.
Like if you want to get Float from double then you can use Float(doubleValue) and Same way if you want to convert float to integer then you can use Int(floatValue).
In your case:
let intValue = UInt8(doubleValue)
Beware that you will lose any value after the decimal point. So, choose a better way. Above conversion is just to help you in understanding.
Note that Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers.
Swift doesn't support implicitly cast anymore in Xcode6 GM. Following answer only apply to Xcode6 beta version.
I don't want to talk about implicitly cast is good or bad, but you can have it if you really want with __conversion()
e.g. If you need UInt8 and Int be able to convert from Double
extension Double {
func __conversion() -> UInt8 { return UInt8(self) }
func __conversion() -> Int { return Int(self) }
// add more if you need to
}
xcrun swift
Welcome to Swift! Type :help for assistance.
1> extension Double {
2. func __conversion() -> UInt8 { return UInt8(self) }
3. }
4> var d = 1.0
d: Double = 1
5> var u8 : UInt8 = d
u8: UInt8 = 1
6>
Note: I won't put this in my production code. I only want to point out it if possible but not recommending it.
using bridgeToObjectiveC() method you can call the methods provided in Objective - C to convert from one primitive data type to another for e.g.
variable_name.bridgeToObjectiveC().intValue
will convert that variable named variable_name to integer
Implicit conversion is possible but with literals only and some conversions are available from the box e.g. Int -> Double:
let a = 3 // Int
let b = 100.5 // Double
// Doesn't work with variables
let c = a * b // Error: Binary operator '*' cannot be applied to operands of type 'Int' and 'Double'
// But this works, because Int(3) literal converts to Double(3.0) implicitly
let d = 3 * b // 301.5
If you want to make backward conversion Double -> Int you should extend Int with ExpressibleByFloatLiteral:
extension Int: ExpressibleByFloatLiteral {
public init(floatLiteral value: Double) {
self.init(value)
}
}
// Double(100.5) converts to Int(100)
let e = a * 100.5 // 300
Even more it's possible to implicitly convert to any type from literals, for instance String -> URLRequest:
extension URLRequest: ExpressibleByStringLiteral {
public init(stringLiteral value: String) {
self.init(url: URL(string: value)!)
}
}
let request: URLRequest = "https://www.google.com"

Resources