dongzhenbi8919 2018-08-31 10:01
浏览 55
已采纳

在cgo中使用strfmon

I'm trying to use the C function strfmon using cgo.

The example C code that works is:

#include <stdio.h>
#include <monetary.h>

int main(void)
{
    char str[100];
    double money = 1234.56;
    strfmon(str, 100, "%i", money);
    printf("%s
", string);
}

The Go code I've written so far is:

package main

// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include <monetary.h>
import "C"
import (
    "fmt"
)

func main() {
    str := [100]C.char{}
    var money C.double = 1234.56
    C.strfmon(str, 100, "%i", money)
    fmt.Printf("%+v
", str)
}

When I go run main.go I get the following error:

./main.go:14:2: unexpected type: ...

I believe the ... refers to the variadic argument in strfmon but I'm not sure how to work around that from Go.

  • 写回答

1条回答 默认 最新

  • douduan3203 2018-08-31 15:40
    关注

    According to the cgo command documentation:

    Calling variadic C functions is not supported. It is possible to circumvent this by using a C function wrapper.

    And strfmon(3p) is indeed a variadic function as indicated by the ... characters in the signature:

    ssize_t strfmon(char *restrict s, size_t maxsize,
       const char *restrict format, ...);
    

    As such, you can create a wrapper function in C which has a fixed number of arguments and calls strfmon(...) as needed, for example:

    package main
    
    // #cgo CFLAGS: -g -Wall
    //
    // #include <locale.h>
    // #include <monetary.h>
    // #include <stdlib.h>
    //
    // size_t format_amount(char * s, size_t maxsize, char * format, double amount)
    // {
    //   setlocale(LC_ALL, "en_US");
    //   return strfmon(s, maxsize, format, amount);
    // }
    //
    import "C"
    import "fmt"
    import "unsafe"
    
    const SIZE = 100
    
    func main() {
      str := C.CString(string(make([]byte, SIZE)))
      money := C.double(1234.56)
      format := C.CString("[%n]")
    
      C.format_amount(str, SIZE-1, format, money) // Call our wrapper here.
      fmt.Printf("OK: %s
    ", C.GoString(str))
      // OK: [$1,234.56]
    
      C.free(unsafe.Pointer(str))
      C.free(unsafe.Pointer(format))
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?