最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++調(diào)用Go方法的字符串傳遞問題及解決方案

 更新時間:2020年11月19日 10:14:35   作者:華為云開發(fā)者社區(qū)  
這篇文章主要介紹了C++調(diào)用Go方法的字符串傳遞問題及解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

摘要:C++調(diào)用Go方法時,字符串參數(shù)的內(nèi)存管理需要由Go側(cè)進(jìn)行深度值拷貝。

現(xiàn)象

在一個APP技術(shù)項目中,子進(jìn)程按請求加載Go的ServiceModule,將需要拉起的ServiceModule信息傳遞給Go的Loader,存在C++調(diào)用Go方法,傳遞字符串的場景。

方案驗證時,發(fā)現(xiàn)有奇怪的將std::string對象的內(nèi)容傳遞給Go方法后,在Go方法協(xié)程中取到的值與預(yù)期不一致。

經(jīng)過一段時間的分析和驗證,終于理解問題產(chǎn)生的原因并給出解決方案,現(xiàn)分享如下。

背景知識

  1. Go有自己的內(nèi)存回收GC機制,通過make等申請的內(nèi)存不需要手動釋放。
  2. C++中為std::string變量賦值新字符串后,.c_str()和.size()的結(jié)果會聯(lián)動變化,尤其是.c_str()指向的地址也有可能變化。
  3. go build -buildmode=c-shared .生成的.h頭文件中定義了C++中Go的變量類型的定義映射關(guān)系,比如GoString、GoInt等。其中GoString實際是一個結(jié)構(gòu)體,包含一個字符指針和一個字符長度。

原理及解釋

通過代碼示例方式解釋具體現(xiàn)象及原因,詳見注釋

C++側(cè)代碼:

//
  // Created by w00526151 on 2020/11/5.
  //
   
  #include <string>
  #include <iostream>
  #include <unistd.h>
  #include "libgoloader.h"
   
  /**
   * 構(gòu)造GoString結(jié)構(gòu)體對象
   * @param p
   * @param n
   * @return
   */
  GoString buildGoString(const char* p, size_t n){
    //typedef struct { const char *p; ptrdiff_t n; } _GoString_;
    //typedef _GoString_ GoString;
    return {p, static_cast<ptrdiff_t>(n)};
  }
   
  int main(){
    std::cout<<"test send string to go in C++"<<std::endl;
   
    std::string tmpStr = "/tmp/udsgateway-netconftemplateservice";
    printf("in C++ tmpStr: %p, tmpStr: %s, tmpStr.size:%lu \r\n", tmpStr.c_str(), tmpStr.c_str(), tmpStr.size());
    {
      //通過new新申請一段內(nèi)存做字符串拷貝
      char *newStrPtr = NULL;
      int newStrSize = tmpStr.size();
      newStrPtr = new char[newStrSize];
      tmpStr.copy(newStrPtr, newStrSize, 0);
   
      //調(diào)用Go方法,第一個參數(shù)直接傳std::string的c_str指針和大小,第二個參數(shù)傳在C++中單獨申請的內(nèi)存并拷貝的字符串指針,第三個參數(shù)和第一個一樣,但是在go代碼中做內(nèi)存拷貝保存。
      //調(diào)用Go方法后,通過賦值修改std::string的值內(nèi)容,等待Go中新起的線程10s后再將三個參數(shù)值打印出來。
      LoadModule(buildGoString(tmpStr.c_str(), tmpStr.size()), buildGoString(newStrPtr, newStrSize), buildGoString(tmpStr.c_str(),tmpStr.size()));
      //修改tmpStr的值,tmpStr.c_str()得到的指針指向內(nèi)容會變化,tmpStr.size()的值也會變化,Go中第一個參數(shù)也會受到影響,前幾位會變成新字符串內(nèi)容。
      //由于在Go中int是值拷貝,所以在Go中,第一個參數(shù)的長度沒有變化,因此實際在Go中已經(jīng)出現(xiàn)內(nèi)存越界訪問,可能產(chǎn)生Coredump。
      tmpStr = "new string";
      printf("in C++ change tmpStr and delete newStrPtr, new tmpStr: %p, tmpStr: %s, tmpStr.size:%lu \r\n", tmpStr.c_str(), tmpStr.c_str(), tmpStr.size());
      //釋放新申請的newStrPtr指針,Go中對應(yīng)第二個string變量內(nèi)存也會受到影響,產(chǎn)生亂碼。
      // 實際在Go中,已經(jīng)在訪問一段在C++中已經(jīng)釋放的內(nèi)存,屬于野指針訪問,可能產(chǎn)生Coredump。
      delete newStrPtr;
    }
    pause();
  }

Go側(cè)代碼:

package main
   
  import "C"
  import (
    "fmt"
    "time"
  )
   
  func printInGo(p0 string, p1 string, p2 string){
    time.Sleep(10 * time.Second)
    fmt.Printf("in go function, p0:%s size %d, p1:%s size %d, p2:%s size %d", p0, len(p0), p1, len(p1), p2, len(p2))
  }
   
  //export LoadModule
  func LoadModule(name string, version string, location string) int {
    //通過make的方式,新構(gòu)建一段內(nèi)存來存放從C++處傳入的字符串,深度拷貝防止C++中修改影響Go
    tmp3rdParam := make([]byte, len(location))
    copy(tmp3rdParam, location)
    new3rdParam := string(tmp3rdParam)
    fmt.Println("in go loadModule,first param is",name,"second param is",version, "third param is", new3rdParam)
    go printInGo(name, version, new3rdParam);
    return 0
  }

Go側(cè)代碼通過-buildmode=c-shared的方式生成libgoloader.so及l(fā)ibgoloader.h供C++編譯運行使用

go build -o libgoloader.so -buildmode=c-shared .

程序執(zhí)行結(jié)果:

test send string to go in C++
    in C++ tmpStr: 0x7fffe1fb93f0, tmpStr: /tmp/udsgateway-netconftemplateservice, tmpStr.size:38
    # 將C++的指針傳給Go,一開始打印都是OK的
    in go loadModule,first param is /tmp/udsgateway-netconftemplateservice second param is /tmp/udsgateway-netconftemplateservice third param is /tmp/udsgateway-netconftemplateservice
    # 在C++中,將指針指向的內(nèi)容修改,或者刪掉指針
    in C++ change tmpStr and delete newStrPtr, new tmpStr: 0x7fffe1fb93f0, tmpStr: new string, tmpStr.size:10
    # 在Go中,參數(shù)1、參數(shù)2對應(yīng)的Go string變量都受到了影響,參數(shù)3由于做了深度拷貝,沒有受到影響。
    in go function, p0:new string eway-netconftemplateservice size 38, p1:        p���  netconftemplateservice size 38, p2:/tmp/udsgateway-netconftemplateservice size 38

結(jié)論

  • 結(jié)論:C++調(diào)用Go方法時,字符串參數(shù)的內(nèi)存管理需要由Go側(cè)進(jìn)行深度值拷貝。即參數(shù)三的處理方式
  • 原因:傳入的字符串GoString,實際是一個結(jié)構(gòu)體,第一個成員p是一個char*指針,第二個成員n是一個int長度。

在C++代碼中,任何對成員p的char*指針的操作,都將直接影響到Go中的string對象的值。

只有通過單獨的內(nèi)存空間開辟,進(jìn)行獨立內(nèi)存管理,才可以避免C++中的指針操作對Go的影響。

ps:不在C++中進(jìn)行內(nèi)存申請釋放的原因是C++無法感知Go中何時才能真的已經(jīng)沒有對象引用,無法找到合適的時間點進(jìn)行內(nèi)存釋放。

本文分享自華為云社區(qū)《C++調(diào)用Go方法的字符串傳遞問題及解決方案》,原文作者:王芾。

到此這篇關(guān)于C++調(diào)用Go方法的字符串傳遞問題及解決方案的文章就介紹到這了,更多相關(guān)C++調(diào)用Go字符串傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹

    C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹

    這篇文章主要介紹了C++中構(gòu)造函數(shù)與析構(gòu)函數(shù)的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • C++中STL的常用算法總結(jié)

    C++中STL的常用算法總結(jié)

    這篇文章主要介紹了C++?STL中一些常見算法的使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • 淺談c語言中類型隱性轉(zhuǎn)換的坑

    淺談c語言中類型隱性轉(zhuǎn)換的坑

    下面小編就為大家?guī)硪黄獪\談c語言中類型隱性轉(zhuǎn)換的坑。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-08-08
  • C++實現(xiàn)LeetCode(146.近最少使用頁面置換緩存器)

    C++實現(xiàn)LeetCode(146.近最少使用頁面置換緩存器)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(146.近最少使用頁面置換緩存器),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • c++11 符號修飾與函數(shù)簽名、函數(shù)指針、匿名函數(shù)、仿函數(shù)、std::function與std::bind

    c++11 符號修飾與函數(shù)簽名、函數(shù)指針、匿名函數(shù)、仿函數(shù)、std::function與std::bind

    這篇文章主要介紹了c++11 符號修飾與函數(shù)簽名、函數(shù)指針、匿名函數(shù)、仿函數(shù)、std::function與std::bind,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • C++中I/O模型之select模型實例

    C++中I/O模型之select模型實例

    這篇文章主要介紹了C++中I/O模型的select模型,實例講述了I/O模型的用法,具有一定的參考借鑒價值,需要的朋友可以參考下
    2014-10-10
  • C++瓦片地圖坐標(biāo)轉(zhuǎn)換的實現(xiàn)詳解

    C++瓦片地圖坐標(biāo)轉(zhuǎn)換的實現(xiàn)詳解

    常見的瓦片地圖有矩形、菱形、正六邊形幾種。此文章主要討論菱形瓦片,也就是大家常說的2.5D,斜45度瓦片地圖。比如《紅警2》、《帝國時代2》都是采用這種技術(shù)
    2022-09-09
  • C++、python和go語言實現(xiàn)的簡單客戶端服務(wù)器代碼示例

    C++、python和go語言實現(xiàn)的簡單客戶端服務(wù)器代碼示例

    這篇文章主要介紹了C++、python和go語言實現(xiàn)的簡單客戶端服務(wù)器代碼示例,本文分別給出了3種語言的客戶端服務(wù)器通信代碼實例,需要的朋友可以參考下
    2015-03-03
  • Qt?事件處理機制的深入理解

    Qt?事件處理機制的深入理解

    本文主要介紹了Qt?事件處理機制的深入理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Opencv?視頻讀取與寫入的實現(xiàn)示例

    Opencv?視頻讀取與寫入的實現(xiàn)示例

    本文將介紹如何使用OpenCV進(jìn)行視頻讀寫。通過閱讀本文,您將了解如何讀取視頻文件、處理視頻幀、寫入視頻文件等操作,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08

最新評論

漾濞| 平远县| 鄂托克前旗| 阿拉善盟| 大荔县| 康定县| 甘谷县| 宜宾县| 正宁县| 云阳县| 金山区| 景洪市| 福清市| 江西省| 扶风县| 琼结县| 当涂县| 文登市| 镇坪县| 华坪县| 皋兰县| 贵州省| 六盘水市| 新泰市| 凤阳县| 泸水县| 远安县| 建始县| 呼和浩特市| 临海市| 龙山县| 竹山县| 辽源市| 陇川县| 宣城市| 宾川县| 定襄县| 浮梁县| 准格尔旗| 古交市| 抚松县|