Home  >  Article  >  Backend Development  >  Detailed explanation of commonly used data conversion and usage in CGO projects

Detailed explanation of commonly used data conversion and usage in CGO projects

藏色散人
藏色散人forward
2022-01-20 17:06:043865browse

This article is provided by the golang tutorial column to introduce you to the commonly used data conversion and use in CGO practical projects. I hope it will be helpful to friends in need!

Preface

You need to deploy the relevant environment and have basic knowledge points. This is not a popular science article, it is mainly for the types used in actual projects. Conversion and use, for the function call parameter transmission and reception of dynamic libraries
1. GO environment, start to support CGO
2. Install g in advance
3. Understand the syntax of GO and C
4 , it is best to know basic makefile or shell syntax (meaning I don’t understand it, I am a noob, and I can only read a rough outline) mainly because I need to use it when debugging C by myself.
If you know everything, please click on the literacy link: chai2010.cn/advanced-go-programmin...

List of basic data types

Detailed explanation of commonly used data conversion and usage in CGO projects

Because GO supports C language calls , so only the conversion with C is listed. As for C, it needs to be converted into C language before it can be called successfully. It should be noted that each C variable is limited to use within one package. If you want to use it across packages, please use GO to encapsulate it. Otherwise, a calling error will be prompted and the C variable cannot be found.

Data type conversion used in the project

#Go string is converted into C

C string is one character The special case of arrays, simply put, is that a character array ending with 0 is a string, so it does not belong to the basic data type.
C.CString is a standard library that calls C. It applies for new memory space and needs to call C.free to release it, otherwise memory leaks will occur.

    var  deviceIp string
    cdeviceIp := C.CString(deviceIp)
    defer C.free(unsafe.Pointer(cdeviceIp))
C's char * /char[] is converted into go's string

Call C's standard library C.GoString, this function will not generate new memory space , creates a copy and does not release memory space.

Convert C byte array to Go string

For example, the type of C is: BYTE sSerialNumber[SERIALNO_LEN];
The way to obtain it is to use append to add Bytes to string

    serialNo := make([]byte, 0)
    for _, v := range sSerialNumber {
        if v != 0 {
            serialNo = append(serialNo, byte(v))
        }
    }

Note the difference between character arrays and strings mentioned earlier.

Go string to C character array

Type: CHAR szKeyFilePath[PU_CERT_FILE_PATH_MAX];

    var keyFilePath = "/home/docker/path/file.jpg"
    for i, b := range keyFilePath {
        szKeyFilePath[i] = C.CHAR(b)
    }

Combined Data Acquisition

When connecting to the data callback of the Huawei camera, the union type data is obtained. When it is obtained as a normal structure, the compiler will always prompt that the structure cannot be found. As a last resort, in the C code After obtaining the data of the union, convert it to the basic data type, and then call Go again. Post a code snippet to get the data from the face recognition callback. Don't worry about the context, just look at how to get the data type.

void CGopfFaceSnapCallBack(CHAR *szBuffer, LONG lSize, void *pUsrData) {
    PU_META_DATA *pstMetaData = 0;
    int ret = Wrapper_IVS_User_GetMetaData(szBuffer, lSize, TARGET, &pstMetaData);
    if (ret == PU_FALSE ){
        return ;
    }
    PU_UserData *pstMetaUserData = pstMetaData->pstMetaUserData;
    char  name[100]={0};
    char  cardID[100]={0};
    for(UINT uIndex = 0; uIndex usValidNumber; ++uIndex){
       //printf("pstMetaData eType : %x\n", pstMetaUserData[uIndex].eType);
        if (pstMetaUserData[uIndex].eType == FACE_INFO){
            strcpy(cardID, pstMetaUserData[uIndex].unMetaData.stFaceInfo.cardID);
            strcpy(name, pstMetaUserData[uIndex].unMetaData.stFaceInfo.name);
            printf("GopfFaceSnapCallBack unMetaData.stFaceInfo cardID : %s\n", pstMetaUserData[uIndex].unMetaData.stFaceInfo.cardID);
            printf("GopfFaceSnapCallBack unMetaData.stFaceInfo name : %s\n", pstMetaUserData[uIndex].unMetaData.stFaceInfo.name);
            GopfFaceSnapCallBack(pstMetaUserData[uIndex].unMetaData.stFaceInfo.cardID,pUsrData);
            break ;
        }
    }
    Wrapper_IVS_User_FreeMetaData(&pstMetaData);
    return ;}

If this code is replaced with Go logic and read directly in Go, it will prompt that unMetaData cannot find the definition. If there are other successful reading methods, please let us know.

Call callback function in C

1. First implement the function with the same data type in Go code, and use //export to export it as a C function. If the callback is not found, , first check whether the data type is correct, and then check whether the trigger condition is met. This step is to receive the C language callback data in Go language, that is, the callback data is obtained in this function.
2. CGO calls the C function. Some colleagues said that this step can be omitted. You can just call the function in the first step directly in Go. I haven't tried it yet. The company's ancestral code is written like this, so I just follow it. used.
3. Just call it directly as a common function in GO language.
Look at the code example:
C function declaration:

typedef VOID (CALLBACK *pfRealDataCallBack)(CHAR *szBuffer, LONG lSize, VOID *pUsrData);

The code of the first step:

//export GopfRealDataCallBackfunc GopfRealDataCallBack(szBuffer *C.CHAR, lSize C.LONG, pUsrData unsafe.Pointer) {
    fmt.Println(szBuffer,lSize,pUsrData)}

The second step:

extern void GopfRealDataCallBack(CHAR *szBuffer, LONG lSize, void *pUsrData);void CGopfRealDataCallBack(CHAR *szBuffer, LONG lSize, void *pUsrData){
    return GopfRealDataCallBack(szBuffer,lSize,pUsrData);}

The third step: C.pfRealDataCallBack(C.CGopfRealDataCallBack) needs to be declared on import C, otherwise the call will not take effect

void* and unsafe.Pointer

unsafe.Pointer is known as all Data type transfer bridges can be considered equivalent at the language level. When void* is encountered, unsafe.Pointer can be used to receive or transmit it. Conversion of specific types requires forced conversion based on the actual type. For example:

lpOutBuff := unsafe.Pointer(C.malloc(1024))

This 1024 can be modified based on the actual situation, and it is not a panacea.

结构体数组的传递

results := (*C.struct_name)(C.malloc(C.size_t(C.sizeof_struct_name * C.int(resLen))))
    defer C.free(unsafe.Pointer(results))

struct_name换成具体的结构体名称,申请了空间要释放,GO检测不到C的部分。

结构体数组遍历获取元素数据

    for i := 0; i <p>struct_name换成具体的结构体名称,uintptr是元素内存地址,根据偏移量获取元素。<code>go
    for i := 0; i <span class="rm-link-color">                      </span>                             </code></p><p class="meta" style="margin: 35px 0px;"><em class="icon tags"></em></p>

The above is the detailed content of Detailed explanation of commonly used data conversion and usage in CGO projects. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:learnku.com. If there is any infringement, please contact admin@php.cn delete