Использование strfmon с cgo - PullRequest
       7

Использование strfmon с cgo

0 голосов
/ 31 августа 2018

Я пытаюсь использовать функцию C strfmon, используя cgo.

Пример кода 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: ...

Я полагаю, что ... относится к аргументу variadic в strfmon, но я не уверен, как обойти это из Go.

1 Ответ

0 голосов
/ 31 августа 2018

Согласно документации команды cgo :

Вызов функций с переменным числом 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))
}
...