溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

CGO項目中常用的數(shù)據(jù)轉(zhuǎn)換怎么使用

發(fā)布時間:2022-01-21 09:12:17 來源:億速云 閱讀:202 作者:iii 欄目:編程語言

這篇文章主要講解了“CGO項目中常用的數(shù)據(jù)轉(zhuǎn)換怎么使用”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“CGO項目中常用的數(shù)據(jù)轉(zhuǎn)換怎么使用”吧!

                           

前言

需要部署好相關(guān)環(huán)境和具備基本的知識點,這并非是一篇科普的文章,主要是針對實際項目中用到的類型轉(zhuǎn)換和使用,針對動態(tài)庫的函數(shù)調(diào)用參數(shù)傳遞和接收
1、GO環(huán)境,啟動支持CGO
2、事先安裝g++
3、看得懂GO和C的語法
4、最好會基本的makefile或者shell語法(表示我不懂,是個菜雞,只會看個大概)主要是自己調(diào)試C需要用到

基本數(shù)據(jù)類型一覽

CGO項目中常用的數(shù)據(jù)轉(zhuǎn)換怎么使用

由于GO支持 C語言的調(diào)用,所以只列出了和C的轉(zhuǎn)換,至于C++,需要轉(zhuǎn)換成C語言才可以成功調(diào)用。需要注意的是:每個C的變量都是限定在一個包內(nèi)使用的,如果想跨包使用,請用GO封裝一層,否則會提示調(diào)用錯誤,找不到這個C變量。

項目中用到的數(shù)據(jù)類型轉(zhuǎn)換

go的string轉(zhuǎn)換成C

C的字符串就是一個字符數(shù)組的特例,簡單的說就是一個字符數(shù)組以0結(jié)尾的數(shù)組就是字符串,所以不屬于基本數(shù)據(jù)類型 。
C.CString是調(diào)用C的標(biāo)準(zhǔn)庫,申請了新的內(nèi)存空間,需要調(diào)用C.free釋放,否則會內(nèi)存泄漏。

    var  deviceIp string
    cdeviceIp := C.CString(deviceIp)
    defer C.free(unsafe.Pointer(cdeviceIp))
C的char * /char[] 轉(zhuǎn)換成go的string

調(diào)用C的標(biāo)準(zhǔn)庫 C.GoString,這個函數(shù)不會產(chǎn)生新的內(nèi)存空間,創(chuàng)建的是一個副本,也不會釋放內(nèi)存空間。

C的字節(jié)數(shù)組轉(zhuǎn)Go的string

比方說C的類型是:BYTE sSerialNumber[SERIALNO_LEN];
獲取的方式就是利用append添加字節(jié)到字符串

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

注意前面提到的字符數(shù)組和字符串的區(qū)別。

Go的string轉(zhuǎn)C的字符數(shù)組

類型:CHAR szKeyFilePath[PU_CERT_FILE_PATH_MAX];

    var keyFilePath = "/home/docker/path/file.jpg"
    for i, b := range keyFilePath {
        szKeyFilePath[i] = C.CHAR(b)
    }
聯(lián)合體的數(shù)據(jù)獲取

接華為攝像頭的數(shù)據(jù)回調(diào)的時候有聯(lián)合體類型數(shù)據(jù)的獲取,當(dāng)作普通結(jié)構(gòu)體獲取的時候編譯會一直提示找不到這個結(jié)構(gòu)體,后面不得已,在C代碼里面獲取到聯(lián)合體的數(shù)據(jù)之后,轉(zhuǎn)換成基本數(shù)據(jù)類型,再重新Go調(diào)用。貼一個代碼片斷,人臉識別回調(diào)獲取的數(shù)據(jù)。不用糾結(jié)前后文,看數(shù)據(jù)類型的獲取就好。

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 < pstMetaData->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 ;}

如果這段代碼換成Go的邏輯,直接在Go里面去讀取的話會提示unMetaData 找不到定義。有其他成功讀取方式的,還請告知。

C的回調(diào)函數(shù)的調(diào)用

1、先Go代碼實現(xiàn)數(shù)據(jù)類型一致的函數(shù),利用//export 導(dǎo)出為C函數(shù),如果發(fā)現(xiàn)回調(diào)沒進(jìn)來,首先檢查一下數(shù)據(jù)類型是否正確,再檢查觸發(fā)條件是否滿足。這一步是為了在Go語言里面接收到C語言的回調(diào)數(shù)據(jù),也就是回調(diào)后的數(shù)據(jù)是在這個函數(shù)里面獲取。
2、CGO調(diào)用C函數(shù),有同事說這一步可以不用,直接在Go里面調(diào)用第一步的函數(shù)就可以,我還沒試過,公司祖?zhèn)鞯拇a就是這么寫的,也就直接照用了。
3、在GO語言里面當(dāng)作常用函數(shù)直接調(diào)用就好。
看代碼示例:
C的函數(shù)聲明:

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

第一步的代碼:

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

第二步:

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

第三步:C.pfRealDataCallBack(C.CGopfRealDataCallBack),需要在import C 上聲明,否則調(diào)用不生效

void*和unsafe.Pointer

unsafe.Pointer號稱是所有數(shù)據(jù)類型的轉(zhuǎn)接橋梁,在語言層面兩個可以認(rèn)為等同的,當(dāng)碰到void*可以用unsafe.Pointer來接收或者傳遞,具體類型的轉(zhuǎn)換,需要根據(jù)實際類型做強轉(zhuǎn)。比方說:

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

這個1024看實際情況修改,不是萬能的。

結(jié)構(gòu)體數(shù)組的傳遞
results := (*C.struct_name)(C.malloc(C.size_t(C.sizeof_struct_name * C.int(resLen))))
    defer C.free(unsafe.Pointer(results))

struct_name換成具體的結(jié)構(gòu)體名稱,申請了空間要釋放,GO檢測不到C的部分。

結(jié)構(gòu)體數(shù)組遍歷獲取元素數(shù)據(jù)
    for i := 0; i < int(resLen); i++ {
        result := (*C.struct_name)(unsafe.Pointer(uintptr(unsafe.Pointer(results)) + uintptr(i*C.sizeof_struct_name)))
    }

struct_name換成具體的結(jié)構(gòu)體名稱,uintptr是元素內(nèi)存地址,根據(jù)偏移量獲取元素。go    for i := 0; i < int(resLen); i++ {        result := (*C.DetectFaceResult)(unsafe.Pointer(uintptr(unsafe.Pointer(results)) + uintptr(i*C.sizeof_DetectFaceResult)))    }                                                  

感謝各位的閱讀,以上就是“CGO項目中常用的數(shù)據(jù)轉(zhuǎn)換怎么使用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對CGO項目中常用的數(shù)據(jù)轉(zhuǎn)換怎么使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

cgo
AI