0

I am trying to pass a string argument from swift function wrapper to C function which takes char*.

This a c function

long swe_fixstar2_ut(char* star, double tjd_ut, long iflag, double* xx, char* serr);

The parameter star must provide for at least 41 characters for the returned star name. If a star is found, its name is returned. This function searches the star name from the txt file.

When imported to Swift function looks like this

swe_fixstar_ut(star: UnsafeMutablePointer<Int8>!, tjd_ut: Double, iflag: int32,
                xx: UnsafeMutablePointer<Double>!, serr: UnsafeMutablePointer<Int8>!)

I want to achieve something like this

public func sweFixStarsUT(star: String, tjdUT: Double, iFlag: Int32) {
      let xx: UnsafeMutablePointer = UnsafeMutablePointer<Double>.allocate(capacity:6)
      let serr:UnsafeMutablePointer = UnsafeMutablePointer<CChar>.allocate(capacity:256)
      swe_fixstar_ut(star, tjdUT, iFlag, xx, serr)
}

I looked around few of the similar questions but it doesn't solve my problem.

Convert a Swift Array of String to a to a C string array pointer

How to pass an array of Swift strings to a C function taking a char ** parameter

Actually this function comes from Swiss ephemeris C library. Here is the link if you guys are interested to look

https://www.astro.com/swisseph/swephprg.htm#_Toc505244846

John
  • 31
  • 5

1 Answers1

4

As far as I read the doc, the parameter star is used for both in and out, so your star of the Swift function should be inout.

And long is imported as Int, and in Apple's 64-bit platforms, it represents 64-bit signed integer type, if it is actually 32-bit, you may need to update the source files of your C code. I assume it as Int.

So, I would write the bridging code like this:

public func sweFixStarsUT(star: inout String, tjdUT: Double, iFlag: Int) {
    let starLen = max(star.utf8.count, 41)
    var starBuf: [CChar] = Array(repeating: 0, count: starLen+1)
    strcpy(&starBuf, star)
    var xx: [Double] = Array(repeating: 0.0, count: 6)
    var serr: [CChar] = Array(repeating: 0, count: 256)
    swe_fixstar2_ut(&starBuf, tjdUT, iFlag, &xx, &serr)
    star = String(cString: starBuf)
}

I prefer using Arrays when passing pointers to a C-function, when the function does not keep the pointers for later use. With using Arrays, you have no need to worry about deallocating.

You can see how the code is converting the input star to an Array of CChar and coverting back the Array into String.

If you find something wrong with this code, please tell me.

OOPer
  • 47,149
  • 6
  • 107
  • 142
  • 1
    I knew who would answer this if I am not fast enough :) – Martin R May 10 '19 at 15:51
  • 1
    Btw, `long` is `Int` on both 32-bit and 64-bit (Apple) platforms. – Martin R May 10 '19 at 15:55
  • Thanks as always, @MartinR. So, the problem is that the OP is using `Int32` for the originally `long` parameter `iFlg`. The library may be written in _long is 32-bit_ environment which may cause some issues in 64-bit environment. – OOPer May 10 '19 at 16:11
  • @OOPer What kind of issues it may bring ? – John May 10 '19 at 17:13
  • @John, when you assume `long` as `Int32` and it's working, the library may be written only for 32-bit platforms. Such libraries may not work in 64-bit environment. If the library is confirmed to work with 64-bit platforms, or your code is meant only for 32-bit platforms, that may not be a problem. – OOPer May 10 '19 at 17:22
  • @OOPer, @OOPer,This library contains swe_set_ephe_path() function which needs to be called at first before using any other functions .I have used `let path = Bundle.main.bundlePath let swePath = UnsafeMutablePointer(mutating: (path as NSString).utf8String) swe_set_ephe_path(swePath)` to call it inside my framework. I have included necessary txt files also but the functions like `swe_fixstars_ut` is not able to search star name from txt file. What may i have been missing? Thanks ! – John May 10 '19 at 17:56
  • I do not know anything about how to use the library, but your usage of `UnsafeMutablePointer.init(mutating:)` is wrong. But that's another issue (`swe_set_ephe_path` would keep the pointer given), you should better start another thread. – OOPer May 10 '19 at 18:54