【问题标题】:Using strfmon with cgo将 strfmon 与 cgo 一起使用
【发布时间】:2018-08-31 10:01:40
【问题描述】:

我正在尝试通过 cgo 使用 C 函数 strfmon。

有效的示例 C 代码是:

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

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

目前我写的 Go 代码是:

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\n", str)
}

当我go run main.go 时出现以下错误:

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

我相信 ... 指的是 strfmon 中的可变参数,但我不确定如何从 Go 中解决这个问题。

【问题讨论】:

  • 没有更多的错误信息
  • ... 指的是 C 函数中的可变参数。看看man strfmon
  • 为什么不使用 x/text/currency 或其他第三方库?
  • 因为我找不到正确格式化某个语言环境的金额的包。例如在法国,欧元符号在金额之后,在德国,它作为金额的前缀

标签: go cgo


【解决方案1】:

根据cgo command documentation:

不支持调用可变 C 函数。可以通过使用 C 函数包装器来规避这一点。

而strfmon(3p) 确实是一个可变参数函数,如签名中的... 字符所示:

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

因此,您可以在 C 中创建一个具有固定数量参数的包装函数,并根据需要调用 strfmon(...),例如:

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\n", C.GoString(str))
  // OK: [$1,234.56]

  C.free(unsafe.Pointer(str))
  C.free(unsafe.Pointer(format))
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    相关资源
    最近更新 更多