定义
过程
类型对应
C语言类型 | CGO类型 | Go语言类型 |
---|---|---|
char | C.char | byte |
singed char | C.schar | int8 |
unsigned char | C.uchar | uint8 |
short | C.short | int16 |
unsigned short | C.ushort | uint16 |
int | C.int | int32 |
unsigned int | C.uint / unsigned int | uint32 |
long | C.long | int32 |
unsigned long | C.ulong | uint32 |
long long int | C.longlong | int64 |
unsigned long long int | C.ulonglong | uint64 |
float | C.float | float32 |
double | C.double | float64 |
size_t | C.size_t | uint |
bool | C._Bool | bool |
struct xx | C.struct_xx | type xx struct |
char * | *C.char | string |
void * | *C.void | unsafe.Pointer |
准备
|- c # c 代码
|- CTPv6.6.8_20220712 # c++ 官方接口
|- generater # go 生成器代码
| - go |
| ---- | def # go 类型和结构体定义
| ---- | demo # go 示例代码
| ---- | lib # c 封装后编译的库文件
| ---- | quote # 行情
| ---- | trade # 交易
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQ7U0UE2-1676773667608)(null)]
调用函数
C++导出函数
- 函数定义
$ nm -g -C thostmduserapi_se.so |grep CreateFtdcMdApi
00000000001de0f0 T CThostFtdcMdApi::CreateFtdcMdApi(char const*, bool, bool)
$ nm -g thostmduserapi_se.so |grep CreateFtdcMdApi
00000000001de0f0 T _ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb
- go 中调用
package main
import (
"fmt"
"os"
)
// 第一步: 定义函数
/*
// thostmduserapi_se 文件名须有 lib 前缀
// cp thostmduserapi_se.so libthostmduserapi_se.so
#cgo linux LDFLAGS: -fPIC -L${SRCDIR} -Wl,-rpath ${SRCDIR} -lthostmduserapi_se -lstdc++
//void* _ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb(char const*, bool, bool);
// bool 定义为 _Bool
void* _ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb(char const*, _Bool, _Bool);
#include <stdlib.h>
#include <stdint.h>
*/
import "C" // 第二步: 引入 cgo
func main() {
path := C.CString("./log/")
os.MkdirAll("./log/", os.ModePerm)
// 第三步: 使用 cgo 调用
var api unsafe.Pointer = C._ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb(path, false, false)
fmt.Println(api)
}
C 导出函数
C++
方法
变为 C 导出函数
- C++
virtual void RegisterFront(char *pszFrontAddress) = 0;
virtual void Init() = 0;
- C
#define DLL_EXPORT extern "C"
#include "../CTPv6.6.8_20220712/ThostFtdcMdApi.h"
#include <iostream>
using namespace std;
DLL_EXPORT void RegisterFront(CThostFtdcMdApi *api, char *pszFrontAddress){
cout << pszFrontAddress << endl;
return api->RegisterFront(pszFrontAddress);
}
DLL_EXPORT void Init(CThostFtdcMdApi *api, char *pszFrontAddress){
cout << "init" << endl;
return api->Init();
}
echo 生成 libctpquote.so 到 go/lib
cd "$( dirname "${BASH_SOURCE[0]}" )"/go/lib
g++ -shared -fPIC -Wl,-rpath . -o libctpquote.so ../../c/quote.cpp thostmduserapi_se.so
/*
void RegisterFront(void*, char*);
*/
func main()
...
front := C.CString("tcp://180.168.146.187:10131")
C.RegisterFront(api, front)
C.Init(api)
...
C.CString: string → *C.char
C.GoString:*C.char → string
C++导出函数 → C
- C
DLL_EXPORT void* CreateFtdcMdApi(const char *pszFlowPath = "", const bool bIsUsingUdp=false, const bool bIsMulticast=false){
cout << pszFlowPath << endl;
return CThostFtdcMdApi::CreateFtdcMdApi(pszFlowPath, bIsUsingUdp, bIsMulticast);
}
- go
// #cgo linux LDFLAGS: -fPIC -L${SRCDIR} -Wl,-rpath ${SRCDIR} -lthostmduserapi_se -lctpquote -lstdc++
# cgo linux LDFLAGS: -fPIC -L${SRCDIR} -Wl,-rpath ${SRCDIR} -lctpquote -lstdc++
// void*_ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb(char const*, _Bool,_Bool);
void*CreateFtdcMdApi(char const*, _Bool,_Bool);
...
// api := C._ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb(path, false, false)
api := C.CreateFtdcMdApi(path, false, false)
响应函数
OnFrontConnected
- C++
virtual void OnFrontConnected(){};
- C
# include "../CTPv6.6.8_20220712/ThostFtdcMdApi.h"
class Quote: CThostFtdcMdSpi{
public:
// 定义响应函数类型
typedef void OnFrontConnectedType();
// 声明响应函数指针的变量
void *_OnFrontConnected;
// 调用函数指针的变量
virtual void OnFrontConnected(){
if (_OnFrontConnected) { ((OnFrontConnectedType*)_OnFrontConnected)(); }
}
};
// #include "../CTPv6.6.8_20220712/ThostFtdcMdApi.h"
#include "quote.h"
...
// 创建 Quote 实例
DLL_EXPORT void* CreateFtdcMdSpi() {
return new Quote();
}
// 注册 Quote 实例给 Api
DLL_EXPORT void RegisterSpi(CThostFtdcMdApi *api, CThostFtdcMdSpi *spi) {
api->RegisterSpi(spi);
}
// 用 Set 函数将 go 函数指针赋值给 C 函数指针
DLL_EXPORT void SetOnFrontConnected(Quote *spi, void *onFunc){
spi->_OnFrontConnected = onFunc;
}
- Cgo
/*
...
void* CreateFtdcMdSpi();
void RegisterSpi(void *, void*);
// 1
void exOnFrontConnected();
// 3
void SetOnFrontConnected(void *, void*);
...
*/
// 2
//export exOnFrontConnected
func exOnFrontConnected() {
fmt.Println("行情接口连接")
}
经过 1 2 go函数转换为C的函数指针, 3 将此指针传递给 C
- go
func main(){
...
var spi unsafe.Pointer = C.CreateFtdcMdSpi()
C.RegisterSpi(api, spi)
C.SetOnFrontConnected(spi, C.exOnFrontConnected)
front := C.CString("tcp://180.168.146.187:10131")
C.RegisterFront(api, front)
...
}
OnRspUserLogin
- C++
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField*pRspInfo, int nRequestID, bool bIsLast) {};
- C
typedef void OnRspUserLoginType(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
void *_OnRspUserLogin;
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {
if (_OnRspUserLogin){
((OnRspUserLoginType *)_OnRspUserLogin)(pRspUserLogin, pRspInfo, nRequestID, bIsLast);
}
};
DLL_EXPORT int ReqUserLogin(CThostFtdcMdApi *api, CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID){
return api->ReqUserLogin(pReqUserLoginField, nRequestID);
}
DLL_EXPORT void SetOnRspUserLogin(Quote *spi, void *onFunc){
spi->_OnRspUserLogin = onFunc;
}
- Cgo
$ nm -g -C ../lib/libctpquote.so |grep OnRspUserLogin
0000000000001a4a W CThostFtdcMdSpi::OnRspUserLogin(CThostFtdcRspUserLoginField*, CThostFtdcRspInfoField*, int, bool)
/*
// 导入接口原类型声明
#cgo CPPFLAGS: -fPIC -I../../CTPv6.6.8_20220712
#include "ThostFtdcUserApiDataType.h"
#include "ThostFtdcUserApiStruct.h"
...
// virtual int ReqUserLogin(CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID)
int ReqUserLogin(void *api, struct CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID);
void SetOnRspUserLogin(void *, void *);
// virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
void exOnRspUserLogin(struct CThostFtdcRspUserLoginField*, struct CThostFtdcRspInfoField*, int, _Bool);
*/
//export exOnRspUserLogin
func exOnRspUserLogin(loginField *C.struct_CThostFtdcRspUserLoginField, rspInfo *C.struct_CThostFtdcRspInfoField, requestID C.int, isLast C._Bool) {
type CThostFtdcRspInfoField struct {
ErrorID int32
ErrorMsg [81]byte
}
info := (*CThostFtdcRspInfoField)(unsafe.Pointer(rspInfo))
fmt.Println("登录: ", info.ErrorID, string(info.ErrorMsg[:]))
}
-
CThostFtdcReqUserLoginField → struct CThostFtdcReqUserLoginField
-
Cgo → go
rspInfo *C.struct_CThostFtdcRspInfoField → (*CThostFtdcRspInfoField)(unsafe.Pointer(rspInfo))
-
go
func main(){
...
C.SetOnRspUserLogin(spi, C.exOnRspUserLogin)
...
type CThostFtdcReqUserLoginField struct {
// 交易日
TradingDay [9]byte
// 经纪公司代码
BrokerID [11]byte
// 用户代码
UserID [13]byte
// 密码
Password [41]byte
// 用户端产品信息
UserProductInfo [11]byte
// 接口端产品信息
InterfaceProductInfo [11]byte
// 协议信息
ProtocolInfo [11]byte
// Mac地址
MacAddress [21]byte
// 动态密码
OneTimePassword [41]byte
// 保留的无效字段
reserve1 [16]byte
// 登录备注
LoginRemark [36]byte
// 终端IP端口
ClientIPPort int32
// 终端IP地址
ClientIPAddress [33]byte
}
f := CThostFtdcReqUserLoginField{}
copy(f.BrokerID[:], "9999")
copy(f.UserID[:], "008105")
copy(f.Password[:], "1")
nRequestID := C.int(1)
C.ReqUserLogin(api, (*C.struct_CThostFtdcReqUserLoginField)(unsafe.Pointer(&f)), nRequestID)
...
}
-
go → Cgo
f CThostFtdcReqUserLoginField → (*C.struct_CThostFtdcReqUserLoginField)(unsafe.Pointer(&f))
接口封装
用正则表达式制作生成器
用 template 生成文件 (插件gotemplate-syntax
高亮)
-
清除 template 标志产生的换行(开始标志放在后,结算标记放在前,中间标志放两边)
[[ if -]] [[- else -]] [[- end ]]
datatype.go
- 示例
/
///TFtdcExchangePropertyType是一个交易所属性类型
/
///正常
#define THOST_FTDC_EXP_Normal '0'
///根据成交生成报单
#define THOST_FTDC_EXP_GenOrderByTrade '1'
typedef char TThostFtdcExchangePropertyType;
// 交易所属性类型
type TThostFtdcExchangePropertyType byte
const THOST_FTDC_EXP_Normal TThostFtdcExchangePropertyType = '0' // 正常
const THOST_FTDC_EXP_GenOrderByTrade TThostFtdcExchangePropertyType = '1' // 根据成交生成报单
type Typedef struct {
Name string
Type string
Length int
Comment string
Define []struct {
Var string
Value string
Comment string
}
}
[[ range $index, $typedef := .]]// [[ .Comment ]]
type [[ .Name ]] [[ toGo .Type .Length ]]
[[ range .Define ]]const [[ .Var ]] [[ $typedef.Name ]] = [[ if eq (len .Value) 1 ]]'[[ .Value ]]'[[ else ]]"[[ .Value ]]"[[ end ]] // [[ .Comment ]]
[[ end ]]
[[ end ]]
模板中 $ = Global, 在循环中引用全局变量: $.globalVar, 全局变量为数组时,需要 range 得到子项.
struct.go
ThostFtdcUserApiStruct.h → struct.go
- 示例
///响应信息
struct CThostFtdcRspInfoField
{
///错误代码
TThostFtdcErrorIDType ErrorID;
///错误信息
TThostFtdcErrorMsgType ErrorMsg;
};
// 信息分发
type CThostFtdcRspInfoField struct {
// 错误代码
ErrorID TThostFtdcErrorIDType
// 错误信息
ErrorMsg TThostFtdcErrorMsgType
}
-
-
///s*(S*)sstructs+(w+)s{([^}]*)} → // $1ntype $2 struct {}
-
///(S*)s*(w+)s+([^;]+) → // $1n$3 $2
-
type Struct struct {
Name string
Comment string
Fields []struct {
Name string
Type string
Comment string
}
}
[[ range .]]// [[ .Comment ]]
type [[ .Name ]] struct {
[[ range .Fields ]]// [[ .Comment ]]
[[ .Name ]] [[ .Type]]
[[ end ]]
}
[[ end ]]
quote.h quote.cpp
ThostFtdcMdApi.h → quote.h quote.cpp
示例
- 调用函数
///用户登录请求
virtual int ReqUserLogin(CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID) = 0;
// 用户登录请求
DLL_EXPORT int ReqUserLogin(CThostFtdcMdApi *api, CThostFtdcReqUserLoginField *pReqUserLoginField, int nRequestID){
cout << "ReqUserLogin" << endl;
return api->ReqUserLogin(pReqUserLoginField, nRequestID);
}
- 响应函数
///登录请求响应
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField*pRspInfo, int nRequestID, bool bIsLast) {};
// 登录请求响应
typedef void OnRspUserLoginType(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
void *_OnRspUserLogin;
virtual void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast){
if (_OnRspUserLogin) {
((OnRspUserLoginType*)_OnRspUserLogin)(pRspUserLogin, pRspInfo, nRequestID, bIsLast);
}
}
// 登录请求响应
DLL_EXPORT void SetOnRspUserLogin(Quote *spi, void *onFunc){
spi->_OnRspUserLogin = onFunc;
}
正则
模板
- quote.h.tpl
# include "../CTPv6.6.8_20220712/ThostFtdcMdApi.h"
class Quote: CThostFtdcMdSpi{
public:
[[ range .On ]]// [[ .Comment ]]
typedef void [[ .Name ]]Type([[ range $idx, $param := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Type ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ end ]]);
void*_[[ .Name ]];
virtual void [[ .Name ]]([[ range $idx, $param := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Type ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ end ]]){
if (_[[ .Name ]]) {
(([[ .Name ]]Type*)_[[ .Name ]])([[ range $idx, $param := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]][[ end ]]);
}
}
[[ end ]]
};
- quote.cpp.tpl
#define DLL_EXPORT extern "C"
#include "quote.h"
#include <iostream>
using namespace std;
DLL_EXPORT void* CreateFtdcMdApi(const char *pszFlowPath = "", const bool bIsUsingUdp=false, const bool bIsMulticast=false){
cout << pszFlowPath << endl;
return CThostFtdcMdApi::CreateFtdcMdApi(pszFlowPath, bIsUsingUdp, bIsMulticast);
}
// 创建 Quote 实例
DLL_EXPORT void* CreateFtdcMdSpi() {
return new Quote();
}
// ******** 调用函数 *********
[[ range .Fn]]// [[ .Comment ]]
DLL_EXPORT [[ .RtnType ]] [[ .Name ]](CThostFtdcMdApi *api[[ range .Params ]], [[ .Type ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ if eq .Var "ppInstrumentID" ]][][[ end ]][[ end ]]){
cout << "[[ .Name ]]" << endl;
return api->[[ .Name ]]([[ range $idx, $param := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]][[ end ]]);
}
[[ end ]]
// **** 用 Set 函数将 go 函数指针赋值给 C 函数指针 ****
[[ range .On ]]// [[ .Comment ]]
DLL_EXPORT void Set[[ .Name ]](Quote *spi, void *onFunc){
spi->_[[ .Name ]] = onFunc;
}
[[ end ]]
quote.go
类型转换
-
c → cgo
c 类型 cgo 类型 转换 struct struct CThostFtdcFensUserInfoField → struct CThostFtdcFensUserInfoField CThostFtdcMdSpi * void * -
c -> go
c go 转换 CThostFtdcMdSpi * unsafe.Pointer struct * *struct CThostFtdcFensUserInfoField →*def.CThostFtdcFensUserInfoField char* string char *[] []string -
go → cgo 调用函数
go cgo 转换 *struct *C.struct_ (*C.struct_%s)(unsafe.Pointer(%s))”, typ, name string *C.char “C.CString(%s)”, name int C.int “C.int(%s)”, name - [ ]string → char *ppInstrumentID[]
// 订阅询价。
func (q *Quote)SubscribeForQuoteRsp(ppInstrumentID []string, nCount int){
instruments := make([]*C.char, len(ppInstrumentID))
for i := 0; i < len(instruments); i++ {
instruments[i] = (*C.char)(unsafe.Pointer(C.CString(ppInstrumentID[i])))
}
C.SubscribeForQuoteRsp(q.api, (**C.char)(unsafe.Pointer(&instruments[0])), C.int(len(instruments)))
}
-
cgo → go 响应函数
cgo go 转换 *C.struct_ *struct “(*def.%s)(unsafe.Pointer(%s))”, typ, name *C.char string “C.GString(%s)”, name C.int int “int(%s)”, name C._Bool bool “bool(%s)”, name
模板
package quote
/*
#cgo CPPFLAGS: -fPIC -I../../CTPv6.6.8_20220712
#include "ThostFtdcUserApiDataType.h"
#include "ThostFtdcUserApiStruct.h"
#cgo linux LDFLAGS: -fPIC -L${SRCDIR}/../lib -Wl,-rpath ${SRCDIR}/../lib -l ctpquote -lstdc++
void* CreateFtdcMdApi(char const*, _Bool, _Bool);
void* CreateFtdcMdSpi();
[[ range .Fn ]]// [[ .Comment ]]
[[ .RtnType ]] [[ .Name ]](void *api[[ range .Params ]], [[ .Type|toCGo ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ if eq .Var "ppInstrumentID" ]][][[ end ]][[ end ]]);
[[ end ]]
[[ range .On ]]// [[ .Comment ]]
void Set[[ .Name ]](void *, void *);
void ex[[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end]][[ .Type|toCGo ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ if eq .Var "ppInstrumentID" ]][][[ end ]][[ end ]]);
[[ end ]]
#include <stdlib.h>
#include <stdint.h>
*/
import "C"
import (
"fmt"
"goctp/def"
"os"
"time"
"unsafe"
)
type Quote struct {
api, spi unsafe.Pointer
// ************ 响应函数变量 ******************
[[ range .On -]]
// [[ .Comment ]]
[[ .Name ]] func([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]] [[ toGoType .Type .Var ]][[ end ]])
[[ end -]]
}
var q *Quote
func NewQuote() *Quote {
if q != nil{
return q
}
q = &Quote{}
path := C.CString("./log/")
os.MkdirAll("./log/", os.ModePerm)
q.api = C.CreateFtdcMdApi(path, false, false)
q.spi = C.CreateFtdcMdSpi()
C.RegisterSpi(q.api, q.spi)
[[ range .On -]]
// [[ .Comment ]]
C.Set[[ .Name ]](q.spi, C.ex[[ .Name ]])
[[- end ]]
return q
}
[[ range .On -]]
// [[ .Comment ]]
//
//export ex[[ .Name ]]
func ex[[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]] [[ if .HasStar ]]*[[ end ]][[ .Type|exToCGo ]][[ end ]]) {
if q.[[ .Name ]] == nil {
fmt.Println("[[ .Name ]]")
} else {
q.[[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ onVar .Type .Var ]][[ end ]])
}
}
[[ end ]]
[[ range .Fn ]]// [[ .Comment ]]
func (q *Quote)[[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]] [[ toGoType .Type .Var ]][[ end ]]){
[[ if and (gt (len .Params) 0) (eq (index .Params 0).Var "ppInstrumentID") -]]
instruments := make([]*C.char, len(ppInstrumentID))
for i := 0; i < len(instruments); i++ {
instruments[i] = (*C.char)(unsafe.Pointer(C.CString(ppInstrumentID[i])))
}
C.[[ .Name ]](q.api, (**C.char)(unsafe.Pointer(&instruments[0])), C.int(len(instruments)))
[[- else -]]
C.[[ .Name ]](q.api[[ range .Params ]], [[ fnVar .Type .Var ]][[ end ]])
[[- end ]]
}
[[ end ]]
trade.h trade.cpp
trade.h.tpl
-
ThostFtdcMdApi
→ThostFtdcTraderApi
-
Quote
→Trade
-
CThostFtdcMdSpi
→CThostFtdcTraderSpi
trade.cpp.tpl
fn函数前加t, set函数前加t, 以避免与 quote 重名
-
quote.h
→trade.h
-
CreateFtdcMdApi(const char *pszFlowPath = "", const bool bIsUsingUdp=false, const bool bIsMulticast=false)
→CreateFtdcTraderApi(const char *pszFlowPath = "")
-
CThostFtdcMdApi::CreateFtdcMdApi
→CThostFtdcTraderApi::CreateFtdcTraderApi
-
CThostFtdcMdApi
→CThostFtdcTraderApi
-
Quote
→Trade
// 创建 Quote 实例
DLL_EXPORT void* CreateFtdcMdSpi() {
return new Quote();
}
DLL_EXPORT void* GetVersion(){
return (void*)CThostFtdcTraderApi::GetApiVersion();
}
// 创建 Trade 实例
DLL_EXPORT void* CreateFtdcTraderSpi() {
return new Trade();
}
trade.go
fn函数前加t, set函数前加t, 以避免与 quote 重名
模板
package trade
/*
#cgo CPPFLAGS: -fPIC -I../../CTPv6.6.8_20220712
#include "ThostFtdcUserApiDataType.h"
#include "ThostFtdcUserApiStruct.h"
#cgo linux LDFLAGS: -fPIC -L${SRCDIR}/../lib -Wl,-rpath ${SRCDIR}/../lib -l ctptrade -lstdc++
void* CreateFtdcTraderApi(char const*);
void* CreateFtdcTraderSpi();
void* GetVersion();
[[ range .Fn ]]// [[ .Comment ]]
[[ .RtnType ]] t[[ .Name ]](void *api[[ range .Params ]], [[ .Type|toCGo ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ if eq .Var "ppInstrumentID" ]][][[ end ]][[ end ]]);
[[ end ]]
[[ range .On ]]// [[ .Comment ]]
void tSet[[ .Name ]](void *, void *);
void [[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end]][[ .Type|toCGo ]] [[ if .HasStar ]]*[[ end ]][[ .Var ]][[ if eq .Var "ppInstrumentID" ]][][[ end ]][[ end ]]);
[[ end ]]
#include <stdlib.h>
#include <stdint.h>
*/
import "C"
import (
"fmt"
"goctp/def"
"os"
"unsafe"
)
type Trade struct {
api, spi unsafe.Pointer
Version string
// ************ 响应函数变量 ******************
[[ range .On -]]
// [[ .Comment ]]
[[ .Name ]] func([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]] [[ toGoType .Type .Var ]][[ end ]])
[[- end]]
}
var t *Trade
func NewTrade() *Trade {
if t != nil{
return t
}
t = &Trade{}
path := C.CString("./log/")
os.MkdirAll("./log/", os.ModePerm)
t.api = C.CreateFtdcTraderApi(path)
t.Version = C.GoString((*C.char)(C.GetVersion()))
fmt.Println(t.Version)
t.spi = C.CreateFtdcTraderSpi()
C.tRegisterSpi(t.api, t.spi)
[[ range .On -]]
C.tSet[[ .Name ]](t.spi, C.[[ .Name ]]) // [[ .Comment ]]
[[ end ]]
return t
}
[[ range .On -]]
//export [[ .Name ]]
func [[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]] [[ if .HasStar ]]*[[ end ]][[ .Type|exToCGo ]][[ end ]]) {
if t.[[ .Name ]] == nil {
fmt.Println("[[ .Name ]]")
} else {
t.[[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ onVar .Type .Var ]][[ end ]])
}
}
[[ end ]]
[[ range .Fn ]]// [[ .Comment ]]
func (t *Trade)[[ .Name ]]([[ range $idx, $p := .Params ]][[ if gt $idx 0 ]], [[ end ]][[ .Var ]] [[ toGoType .Type .Var ]][[ end ]]){
C.t[[ .Name ]](t.api[[ range .Params ]], [[ fnVar .Type .Var ]][[ end ]])
}
[[ end ]]
byte to Json
// 交易用户登录统计类型类型
type TShfeFtdcLoginStatTypeType byte
// JSON 转换
func (t TShfeFtdcLoginStatTypeType) MarshalJSON() ([]byte, error) {
return json.Marshal(strings.Trim(string(t), "x00"))
}
// 按同一用户统计
const SHFE_FTDC_RLST_ByUser TShfeFtdcLoginStatTypeType = '0'
// 按同一IPMAC地址统计
const SHFE_FTDC_RLST_ByAddress TShfeFtdcLoginStatTypeType = '1'
[…]byte 转 string 再转 json
// 转换函数,注意去掉尾部的 x00
func getGBK(bs []byte) string {
str, _ := simplifiedchinese.GBK.NewDecoder().String(strings.Trim(string(bs), "x00"))
return str
}
// 交易所交易员代码类型
type TShfeFtdcTraderIDType [21]byte
// JSON 转换
func (t TShfeFtdcTraderIDType) MarshalJSON() ([]byte, error) { return json.Marshal(getGBK(t[:])) }
原文地址:https://blog.csdn.net/along1976/article/details/129108041
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_24046.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!