精华内容
下载资源
问答
  • 一份示例代码,向你展示了如何通过字符串调用同名函数
  • C++ 根据字符串 调用同名函数

    千次阅读 2016-09-02 17:18:52
    根据字符串调用字符串同名函数: #include #include #include typedef void (*pFunc)(); std::map strFuncMap; void func1() { printf("this is func1!\n"); } void func2() { printf("this is func2!\...

    根据字符串,调用与字符串同名函数:

    #include <map>
    #include <string>
    #include <iostream>
    
    typedef void (*pFunc)();
    std::map<std::string, pFunc> strFuncMap;
    
    void func1()
    {
    	printf("this is func1!\n");
    }
    
    void func2()
    {
    	printf("this is func2!\n");
    }
    
    void buildMap()
    { 
    	strFuncMap["func1"] = &func1; 
    	strFuncMap["func2"] = &func2;
    }
    
    void callFunc(const std::string& str) 
    { 
    	if(strFuncMap.count(str))
    		(*strFuncMap[str])();
    	else
    		std::cout << "unsupported function str : " << str.c_str() << "\n" << std::endl;
    }
    
    int main()
    {
    	buildMap();
    	//begin call func
    	callFunc("func1");
    	callFunc("func2");
    	callFunc("func3");
    
    	system("pause");
    	return 0;
    }

    输出结果:

    this is func1!
    this is func2!
    unsupported function str : func3


    展开全文
  • 上一期的那个有趣的小代码你们完成了吗?是不是初步从中感受到了学习...这次Python入门的第三波干货,我们将紧接着上次的函数继续聊下去,在说函数之前,我们先补充一下字符串的一些知识。字符串1. 创建和访问字符串...
    274407d5a47d61669fa66b89be87fbe2.gif3d50360bfb36b00ba082e2947d45d822.png

    上一期的那个有趣的小代码你们完成了吗?是不是初步从中感受到了学习编程的乐趣?

    不过,这次的内容较之前会有那么一点点难以理解,大家可能要感受到一些苦恼。

    但还是那句话,学习编程是非常不易而且煎熬的,煎熬是暂时的,在你想放弃的时候,其实你离成功只差了一步。

    这次Python入门的第三波干货,我们将紧接着上次的函数继续聊下去,在说函数之前,我们先补充一下字符串的一些知识。

    39aeb08aff93a312361507e24c98b20e.png587c6d6097de761dd0fb5bd37ee32520.png

    字符串

    9ad2da70adf5b9612b09c3c70147172d.png

    1. 创建和访问字符串

    简单来说,字符串就是引号内的一切东西,引号可以是单引号或者双引号,但必须是成对且对应的。与C语言不同的是,Python中没有字符的概念,所谓字符,就是长度为1的字符串。

    和之前学的列表和元组一样,切片也可以应用在字符串上。

    1b22daa4df062777db03c765fb2232c6.png74065515629f7ff24df4964d257e0520.png9ad2da70adf5b9612b09c3c70147172d.png

    2.字符串拼接

    字符串和元组一样,一旦创建下来就不能直接对它们进行修改了,但对于字符串,我们可以用字符串拼接的方法。

    ee52b0d629d25a9e41f544c86377d879.png234304ba64f9dc218d60812ca18815fd.png9ad2da70adf5b9612b09c3c70147172d.png

    3.字符串格式化

    3d50360bfb36b00ba082e2947d45d822.png

    format()方法

    format()方法接受位置参数和关键字参数(下面的函数中会详细讲解)。

    举个例子:

    cb9337152fde357c0267e45b878b3dc2.pnga47902aba4f8fbcd93a0ac99e387cd23.png

    格式化操作符:%

    760ce29cc50186906f1a365c07243599.png

    举个例子:

    4d6409edfb8df4bdd0ac76903e86aa43.pngeb1267dda28314b0bddef417ea7f3e88.png3d50360bfb36b00ba082e2947d45d822.png

    字符串的操作方法在以后的学习中可是非常有用的,随着深入的学习,我们还会学习功能更强大同时也比较难的方法。不过,学的越深乐趣越大哦!

    接下来,我们就继续聊上一期没有说完的函数吧!

    39aeb08aff93a312361507e24c98b20e.png587c6d6097de761dd0fb5bd37ee32520.png

    函数的参数

    9ad2da70adf5b9612b09c3c70147172d.png

    1.位置参数

    位置参数须以正确的位置传入函数。调用时的数量必须和声明时的一样。

    8041e1cd62b4e681ad8e7c52ff59a076.png5f6d3c269f5a11e0f643b12d92adf28e.png9ad2da70adf5b9612b09c3c70147172d.png

    2. 关键字参数:

    关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。

    1e805e82ff88222e7c8d260e58e0a1f6.pngca4eb6906f9c3533fb9e838b0ffa70e8.png9ad2da70adf5b9612b09c3c70147172d.png

    3.默认参数:

    默认参数其实就是在定义函数的时候,给参数赋予一个默认的值,调用函数时,默认参数的值如果没有传入,则就会输出默认值。

    下例会打印默认的sex,如果sex没有被传入:

    cdd944acf2e9853b40032c7a17c50912.pngf08fd952a78219bc44d0208be4e719db.png9ad2da70adf5b9612b09c3c70147172d.png

    4.不定长参数:

    当你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述参数不同,声明时不会命名,仅需要在参数前边加上星号(*)即可。

    举个例子:

    d94d81d24ab50927174f9287a748c491.png261093b0ec9e149fefa77dbe073a5ab0.png

    其实Python就是把不定长参数的参数们打包成了一个元组,使用的时候,只需要使用操作元组的方法就行了。*就是起了打包的作用,其实它也有解包的作用哦!举个例子,如果你想把一个列表a传入fun()函数的不定长参数*tuples中,直接调用fun(a)时会出错,这个时候,只需在列表a前面加上*,把列表里的值“解”出来即可。

    79d0488261eaae02f8fb030a58acd254.png27721e3415d16f1c2f75dfac6795a91d.png

    当不定长参数前面加两个星号(**)时,这两个星号(**)的作用就是讲参数们打包成字典的形式。同样的,使用的时候,只需要使用操作字典的方法就行了。

    e96c7f7cbf76cda1c56c71d1c9d4a443.png5790dbe58d320c6388c4afc88a8d8276.png587c6d6097de761dd0fb5bd37ee32520.png

     函数的返回值

    3d50360bfb36b00ba082e2947d45d822.png

    要想获取函数的执行结果,就可以用return语句把结果返回。

    注意:

    1.  函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束。

    2.  如果未在函数中指定return,那这个函数的返回值为None  。

    3.  return可以返回列表、字典等对象,当返回多个对象时,解释器会把这多个对象组装成一个元组作为一个一个整体结果输出。

    下面是例子:

    1a1bcf62fb69508735cbbd6b92988de6.png904d843de65b60c358f29bdd41dccc86.png39aeb08aff93a312361507e24c98b20e.png587c6d6097de761dd0fb5bd37ee32520.png

    内嵌函数和函数的作用域

    嘿!敲黑板!难点来咯

    9ad2da70adf5b9612b09c3c70147172d.png

    1.内嵌函数:

    Python允许在函数内部创建另一个函数,这种函数叫做内嵌函数。

    举个例子

    ad62b270ad44b250c7e405dc0c45bbea.pngaef626ac8c9f0d66780a2a2cc33a4dd1.png

    需要注意的是,内嵌函数是不能直接调用的。如果用fun2()调用,则会报错。

    d4dc49d6429b8c805abdf9021c7f0cb5.png9ad2da70adf5b9612b09c3c70147172d.png

    2. 函数的作用域:

    3d50360bfb36b00ba082e2947d45d822.png

    python中的作用域分4种情况:

            L:local,局部作用域,即函数中定义的变量;

            E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;

            G:global,全局变量,就是函数外定义的变量;

           B:built-in,系统固定模块里面的变量,比如int等。

    39aeb08aff93a312361507e24c98b20e.png

    搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。

    要注意的是,local和enclosing是相对的,enclosing变量相对上层来说也是local。

    函数的作用域在理解起来会比较困难,其实简单来说,就是作用域越小越难以被调用,调用变量时能调用哪些变量取决于它的位置在什么作用域内,大家需要多多思考。举个例子:

    55b864f3f841aa109aeab37aa5bd68a0.png9ad2da70adf5b9612b09c3c70147172d.png

    3.global关键字和nonlocal关键字

    当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,例如:

    1538ab1923516231803cc6a0c89bdeb0.png

    global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了。

    e8870b56f1c970d90937a85f709f7290.png587c6d6097de761dd0fb5bd37ee32520.png

    递归函数

    3d50360bfb36b00ba082e2947d45d822.png

    定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

    递归是一个特别好用的方法,它可以使你的代码更加简洁、精炼。但是,想要掌握它也是不太容易的,需要注意的一点就是,在使用递归函数的时候,既要学会调用自己,也要学会从中“蹦出来”。

    举个求阶乘的例子:

    b3c9d7f7363783ee9f1fa766c69fd0ef.png

    用递归方法写出的代码是不是要比常规方法简短精炼许多呢?是不是Python写出的代码比C语言的代码也简短易懂许多呢?

    39aeb08aff93a312361507e24c98b20e.png587c6d6097de761dd0fb5bd37ee32520.png

    内置函数

    Python拥有非常多的内置函数,我们在这里就简单介绍两种比较实用的BIF。

    9ad2da70adf5b9612b09c3c70147172d.png

    1. filter()

    filter其实是一个过滤器,它可以帮助你筛选数据,它有两个参数。第一个参数可以是一个函数或者是None,如果是函数的话,则将第二个可迭代对象的每一个元素作为函数的参数进行计算,把返回值为True的值筛选出来;如果第一个参数是None,则直接将第二个参数中为True的值筛选出来。

    举个例子:

    1fde978853350d012f9d59045bb76cc1.png9ad2da70adf5b9612b09c3c70147172d.png

    2.map()

    map在这里可不是地图的意思,它也有两个参数,分别是一个函数和一个可迭代对象,它的作用就是将可迭代对象中的每个元素作为函数的参数进行运算。举个例子:

    335de18cdb051e150cf9c6a53346b1f0.png

    注意,filter()和map()返回的是一个迭代器,需要用list()输出。

    3d50360bfb36b00ba082e2947d45d822.png

    最后,给大家留个小练习,分别用普通方法和递归函数的方法求斐波那契数列的前20项和。(没有思路就去百度呦!!!)

    817e10857b1ce2b17281c670bb7c3553.png

    执行编辑 | 段航博

    责任编辑 | 于文博

    7ec16700c0c1eddae30c7bdabfc0f157.png
    展开全文
  • C++ 调用Java方法基本使用请参考: ... 一、定义Java 方法: ... return "C++调用Java testString"; } public static String testStaticString(){ return "C++调用Java testStaticString"; } ...

    C++ 调用Java方法基本使用请参考:

    https://blog.csdn.net/u011905195/article/details/112393826

    一、定义Java 方法:

     

    public String testString(){
     
        return "C++调用Java testString";
    }

    public static String testStaticString(){
     
        return "C++调用Java testStaticString";
    }

    二、 C++进行调用

    void testString(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetMethodID(jclazz, "testString",
                                               "()Ljava/lang/String;");
        /**
         * obj:参数是对象
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        jstring result = (jstring) env->CallObjectMethod(thiz, jmethodID);
        LOGD("JniNative返回数据:%s",jstring2string(env,result).c_str());
    }

    void testStaticString(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetStaticMethodID(jclazz, "testStaticString",
                                                     "()Ljava/lang/String;");
        /**
         * clazz:参数是类
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        jstring result = (jstring) env->CallStaticObjectMethod(jclazz, jmethodID);
        LOGD("JniNative返回数据:%s",jstring2string(env,result).c_str());
    }

    三、把获取到的jstring 转成 字符串

    string jstring2string(JNIEnv *env, jstring jStr) {
        if (!jStr)
            return "";

        const jclass stringClass = env->GetObjectClass(jStr);
        const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
        const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));

        size_t length = (size_t) env->GetArrayLength(stringJbytes);
        jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);

        std::string ret = std::string((char *)pBytes, length);
        env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);

        env->DeleteLocalRef(stringJbytes);
        env->DeleteLocalRef(stringClass);
        return ret;
    }

     

    四、主要的代码

    Java部分

     

    package com.example.jnidemo;
    
    import android.util.Log;
    
    public class JniNative {
        private static final String TAG = "JniNative";
        // Used to load the 'native-lib' library on application startup.
    
        static {
            System.loadLibrary("native-lib");
        }
        /**
         * A native method that is implemented by the 'native-lib' native library,
         * which is packaged with this application.
         */
        public native String stringFromJNI();
    
        public void testVoid(){
            Log.e(TAG,"C++调用Java testVoid");
        }
    
        public static void testStaticVoid(){
            Log.e(TAG,"C++调用Java testStaticVoid");
        }
    
        public int testInt(){
            Log.e(TAG,"C++调用Java testInt");
            return 0;
        }
    
        public static int testStaticInt(){
            Log.e(TAG,"C++调用Java testStaticInt");
            return 0;
        }
    
        public String testString(){
            Log.e(TAG,"C++调用Java testString");
            return "C++调用Java testString";
        }
    
        public static String testStaticString(){
            Log.e(TAG,"C++调用Java testStaticString");
            return "C++调用Java testStaticString";
        }
    
    }
    

    C ++部分:

    #include <jni.h>
    #include <string>
    #include "common/logjni.h"
    using namespace std;
    
    void testVoid(JNIEnv *env,jobject thiz);
    static void testStaticVoid(JNIEnv *env,jobject thiz);
    void testInt(JNIEnv *env,jobject thiz);
    static void testStaticInt(JNIEnv *env,jobject thiz);
    void testString(JNIEnv *env,jobject thiz);
    void testStaticString(JNIEnv *env,jobject thiz);
    string jstring2string(JNIEnv *env, jstring jStr);
    extern "C"
    JNIEXPORT jstring JNICALL
    Java_com_example_jnidemo_JniNative_stringFromJNI(JNIEnv *env, jobject thiz) {
        // TODO: implement stringFromJNI()
        std::string hello = "Hello from C++";
        testVoid(env,thiz);
        testStaticVoid(env,thiz);
        testInt(env,thiz);
        testStaticInt(env,thiz);
        testString(env,thiz);
        testStaticString(env,thiz);
        return env->NewStringUTF(hello.c_str());
    }
    
    void testVoid(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetMethodID(jclazz, "testVoid",
                                               "()V");
        /**
         * obj:参数是对象
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        env->CallVoidMethod(thiz, jmethodID);
    }
    
    static void testStaticVoid(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetStaticMethodID(jclazz, "testStaticVoid",
                                               "()V");
        /**
         * clazz:参数是类
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        env->CallStaticVoidMethod(jclazz, jmethodID);
    }
    
    void testInt(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetMethodID(jclazz, "testInt",
                                               "()I");
        /**
         * obj:参数是对象
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        env->CallIntMethod(thiz, jmethodID);
    }
    
    static void testStaticInt(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetStaticMethodID(jclazz, "testStaticInt",
                                                     "()I");
        /**
         * clazz:参数是类
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        env->CallStaticIntMethod(jclazz, jmethodID);
    }
    
    void testString(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetMethodID(jclazz, "testString",
                                               "()Ljava/lang/String;");
        /**
         * obj:参数是对象
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        jstring result = (jstring) env->CallObjectMethod(thiz, jmethodID);
        LOGD("JniNative返回数据:%s",jstring2string(env,result).c_str());
    }
    
    void testStaticString(JNIEnv *env,jobject thiz){
        //获取java对象类
        jclass jclazz = env->GetObjectClass(thiz);
        /**
         * 获取java对象方法ID
         * clazz:对象类
         * name:方法名
         * sig:方法签名
         */
        jmethodID jmethodID = env->GetStaticMethodID(jclazz, "testStaticString",
                                                     "()Ljava/lang/String;");
        /**
         * clazz:参数是类
         * methodID: 方法名ID
         * ... :动态参数(有几个就传几个对应类型的参数)
         */
        jstring result = (jstring) env->CallStaticObjectMethod(jclazz, jmethodID);
        LOGD("JniNative返回数据:%s",jstring2string(env,result).c_str());
    }
    
    string jstring2string(JNIEnv *env, jstring jStr) {
        if (!jStr)
            return "";
    
        const jclass stringClass = env->GetObjectClass(jStr);
        const jmethodID getBytes = env->GetMethodID(stringClass, "getBytes", "(Ljava/lang/String;)[B");
        const jbyteArray stringJbytes = (jbyteArray) env->CallObjectMethod(jStr, getBytes, env->NewStringUTF("UTF-8"));
    
        size_t length = (size_t) env->GetArrayLength(stringJbytes);
        jbyte* pBytes = env->GetByteArrayElements(stringJbytes, NULL);
    
        std::string ret = std::string((char *)pBytes, length);
        env->ReleaseByteArrayElements(stringJbytes, pBytes, JNI_ABORT);
    
        env->DeleteLocalRef(stringJbytes);
        env->DeleteLocalRef(stringClass);
        return ret;
    }
    展开全文
  • 王芾https://my.oschina.net/u/4526289/blog/4722189现象在一个APP技术项目中,子进程按请求加载Go的ServiceModule,将需要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go方法,传递字符串的场景。...

    (给CPP开发者加星标,提升C/C++技能)

    来源:王芾https://my.oschina.net/u/4526289/blog/4722189

    现象

    在一个APP技术项目中,子进程按请求加载Go的ServiceModule,将需要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go方法,传递字符串的场景。

    方案验证时,发现有奇怪的将std::string对象的内容传递给Go方法后,在Go方法协程中取到的值与预期不一致。

    经过一段时间的分析和验证,终于理解问题产生的原因并给出解决方案,现分享如下。

    背景知识

    1. Go有自己的内存回收GC机制,通过make等申请的内存不需要手动释放。

    2. C++中为std::string变量赋值新字符串后,.c_str()和.size()的结果会联动变化,尤其是.c_str()指向的地址也有可能变化。

    3. go build -buildmode=c-shared .生成的.h头文件中定义了C++中Go的变量类型的定义映射关系,比如GoString、GoInt等。其中GoString实际是一个结构体,包含一个字符指针和一个字符长度。

    原理及解释

    通过代码示例方式解释具体现象及原因,详见注释

    C++侧代码:

    //  // Created by w00526151 on 2020/11/5.  //  #include   #include   #include   #include "libgoloader.h"     /**   * 构造GoString结构体对象   * @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新申请一段内存做字符串拷贝          char *newStrPtr = NULL;          int newStrSize = tmpStr.size();          newStrPtr = new char[newStrSize];          tmpStr.copy(newStrPtr, newStrSize, 0);             //调用Go方法,第一个参数直接传std::string的c_str指针和大小,第二个参数传在C++中单独申请的内存并拷贝的字符串指针,第三个参数和第一个一样,但是在go代码中做内存拷贝保存。          //调用Go方法后,通过赋值修改std::string的值内容,等待Go中新起的线程10s后再将三个参数值打印出来。          LoadModule(buildGoString(tmpStr.c_str(), tmpStr.size()), buildGoString(newStrPtr, newStrSize), buildGoString(tmpStr.c_str(),tmpStr.size()));          //修改tmpStr的值,tmpStr.c_str()得到的指针指向内容会变化,tmpStr.size()的值也会变化,Go中第一个参数也会受到影响,前几位会变成新字符串内容。          //由于在Go中int是值拷贝,所以在Go中,第一个参数的长度没有变化,因此实际在Go中已经出现内存越界访问,可能产生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中对应第二个string变量内存也会受到影响,产生乱码。          // 实际在Go中,已经在访问一段在C++中已经释放的内存,属于野指针访问,可能产生Coredump。          delete newStrPtr;      }      pause();  }

    Go侧代码:

    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的方式,新构建一段内存来存放从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侧代码通过-buildmode=c-shared的方式生成libgoloader.so及libgoloader.h供C++编译运行使用

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

    程序执行结果:

      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++中,将指针指向的内容修改,或者删掉指针  in C++ change tmpStr and delete newStrPtr, new tmpStr: 0x7fffe1fb93f0, tmpStr: new string, tmpStr.size:10   # 在Go中,参数1、参数2对应的Go string变量都受到了影响,参数3由于做了深度拷贝,没有受到影响。  in go function, p0:new string eway-netconftemplateservice size 38, p1:        p���  netconftemplateservice size 38, p2:/tmp/udsgateway-netconftemplateservice size 38

    结论

    1. 结论:C++调用Go方法时,字符串参数的内存管理需要由Go侧进行深度值拷贝。即参数三的处理方式

    2. 原因:传入的字符串GoString,实际是一个结构体,第一个成员p是一个char*指针,第二个成员n是一个int长度。

    在C++代码中,任何对成员p的char*指针的操作,都将直接影响到Go中的string对象的值。

    只有通过单独的内存空间开辟,进行独立内存管理,才可以避免C++中的指针操作对Go的影响。

    ps:不在C++中进行内存申请释放的原因是C++无法感知Go中何时才能真的已经没有对象引用,无法找到合适的时间点进行内存释放。

    - EOF -

    推荐阅读  点击标题可跳转

    1、C++ vector详解

    2、C++之父:C++的成功属于意料之外,C++11是转折点

    3、不要再误解C++ volatile了

    关于 C++调用Go方法,欢迎在评论中和我探讨。觉得文章不错,请点赞和在看支持我继续分享好文。谢谢!

    关注『CPP开发者』

    看精选C++技术文章 . 加C++开发者专属圈子

    ↓↓↓

    9b4be06fb42c6e461aaf9ae9eba60967.png

    点赞和在看就是最大的支持❤️

    展开全文
  • 已知strcpy函数的原型是 char *strcpy(char *strDest, const char *strSrc); 其中strDest是目的字符串,...(1)不调用C++/C的字符串库函数,请编写函数strcpy char*strcpy(char*strDest,constchar*strSrc) { a...
  • 已知strcpy函数的原型是 char *strcpy(char *strDest, const char *strSrc);...要求:不调用C++/C的字符串库函数,请编写函数 strcpy#include&lt;iostream&gt; using namespace std; char *strcpy(char ...
  • C++函数源代码里 用MeterArr="aaaa";不行 改成 for(int i=0;i;i++) *(MeterArr+i) = 'a'; *(MeterArr+5)='\0'; 且不能为MeterArr额外申请空间,例如 char *MeterArr = new char[6]; for(int i=0;...
  • ...这是脚本的的基础,有了这个接口,就可以使用lua、python等脚本动态调用C++程序中的函数,只要把字符串传到程序中解析就可以了。 这是一个思路例子,完善的工作就是细节的工作了。
  • C++ 字符串 对象 C++ 字符串 对象 创建方法 C++ 字符串 对象 输出到控制台 C++ 字符串 拼接 ...C++ 字符串 方法调用 ( 栈内存对象 ) C++ 字符串 方法调用 ( 堆内存对象 ) C / C++ 字符串 完整代码示例
  • androidJNI调用c++字符串

    2019-07-24 19:43:10
    在Android中用C/C++开发一部分功能时,有时候要把参数...c/c++写的代码出问题时候,程序会崩溃,不容易找错,所以建议调用时候要多加LOGI打印,在关键调用地方记得要添加返回 值,这样能够省掉很多时间来找错误。 ...
  • c++调用函数,返回字符串数组

    千次阅读 2019-04-20 17:39:13
    c++调用函数,返回字符串数组 输出结果: a 1 v a 1 v 请按任意键继续... 代码如下: char str_1[20]; char w[20]; int a[10] = {1,2}; char * happy() { sprintf(str_1,"a %d v",a[0]); ...
  • 通过检查发现, native C++的 定义的函数参数不对,应该把 jobject 改为 jclass, 则运行通过。 更改如下 native C++ 源码 extern "C" JNIEXPORT jstring JNICALL Java_...
  • 最近这几天,弄这个问题。  C#貌似仅支持双字符的unicode编码,而C++中是单字符的编码,因此,接口函数应使用LPTSTR,C#使用string进行调用
  • 已知strcpy的函数原型:char *strcpy(char *strDest,const char *...不调用C++/C的字符串库函数,实现字符串复制函数strcpy。  一种方法: char *strcpy(char *strDest, const char *strSrc)//源字符串参数用const修
  • 一、字符数组  C语言中可以设置一个二维数组,例如str[3][30],大小为3x30,即有3行30列,每...例如:有三个字符串,要求找出其中最大者(要求用函数调用) #include #include using namespace std; int main() {
  • C++中头文件声明。#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)#include #include "platform/android/jni/JniHelper.h"#include #endif<2>C++中函数实现(jstring转const char*)。#if (CC_TARGET_PLATFORM...
  • Labview调用C++编写的dll实现字符串数组的传递,C++和Labview实现源代码,开发环境:VS2010+Labview2015
  • 摘要:C++调用Go方法时,字符串参数的内存管理需要由Go侧进行深度值拷贝。 现象 在一个APP技术项目中,子进程按请求加载Go的ServiceModule,将需要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go方法,...
  • C++里,字符串要占用内存的。C++创建字符串,并传给C#,就会造成内存泄露...被调用C++字符串内容,填充到指定缓冲区去; 调用者从缓冲区能得到结果,也知道如何清理缓冲(C#自己会用垃圾回收),没有内存泄露问...
  • C#代码using System;using System.Collections.Generic;using System.Text;namespace TestClassLibrary{public class Test{public int TestAdd(int x, int y){return x + y;}public string TestString...}}}C++
  • 摘要:C++调用Go方法时,字符串参数的内存管理需要由Go侧进行深度值拷贝。现象在一个APP技术项目中,子进程按请求加载Go的ServiceModule,将需要拉起的ServiceModule信息传递给Go的Loader,存在C++调用Go方法,传递...
  • 现在有这样一种情景,假如C#调用C++接口需要返回一个字符串。因为字符串是不定长的,因此传递一个定长的字符串进去是不合适的。 因此需要一种间接的做法,简单来说就是C#定义一个创建空字符串的接口,传递这个...
  • reverse(s.begin(),s.end()) #include<bits/stdc++.h> using namespace std; int main(){ string s="qqaa"; reverse(s.begin(),s.end());//该函数包含在<algorithm>头文件中 ......
  • C++拆分字符串

    千次阅读 2018-04-08 15:12:00
    首次调用时,_str指向要分解的字符串,之后再次调用要把_str设成NULL。strtok是非线程安全函数。 vector&lt;std::string&gt; split(const string &amp;str, const string &amp;...
  • C#调用C++Dll字符串返回为空的问题

    千次阅读 2013-07-26 16:53:34
    错误代码 BOOL C_AV_ImagePath(TCHAR* inpath,TCHAR* outpath) {  BOOL bRet=false;  outpath=_T("\\Program Files\\Caputrue\\temp%d.bmp");  return bRet;...C++ xxx.h extern "C" __declspec(dllex

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,738
精华内容 1,095
关键字:

c++调用字符串

c++ 订阅