启闭阀

    g++动态编译的程序报错怎么办?

      发布时间:2019-09-17

      第一步,我先从简单的调用出发,定义了一个简单的函数,该函数仅仅实现一个整数加法求和:

      LIBEXPORT_API int mySum(int a,int b){ return a+b;}
      C# 导入定义:

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
      public static extern int mySum (int a,int b);
      }
      在C#中调用测试:

      int iSum = RefComm.mySum(,);

      运行查看结果iSum为5,调用正确。第一步试验完成,说明在C#中能够调用自定义的动态链接库函数。

      第二步,我定义了字符串操作的函数(简单起见,还是采用前面的函数名),返回结果为字符串:

      LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a); return a;}
      C# 导入定义:

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Auto,
      CallingConvention=CallingConvention.StdCall)]
      public static extern string mySum (string a, string b);
      }
      在C#中调用测试:

      string strDest="";
      string strTmp= RefComm.mySum("45", strDest);

      运行查看结果 strTmp 为"45",但是strDest为空。我修改动态链接库实现,返回结果为串b:

      LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a) return b;}
      修改 C# 导入定义,将串b修改为ref方式:

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)]
      public static extern string mySum (string a, ref string b);
      }
      在C#中再调用测试:

      string strDest="";
      string strTmp= RefComm.mySum("45", ref strDest);
      运行查看结果 strTmp 和 strDest 均不对,含不可见字符。再修改 C# 导入定义,将CharSet从Auto修改为Ansi:

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
      public static extern string mySum (string a, string b);
      }
      在C#中再调用测试:

      string strDest="";
      string strTmp= RefComm. mySum("45", ref strDest);
      运行查看结果 strTmp 为"45",但是串 strDest 没有赋值。第二步实现函数返回串,但是在函数出口参数中没能进行输出。再次修改 C# 导入定义,将串b修改为引用(ref):

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
      public static extern string mySum (string a, ref string b);
      }

      运行时调用失败,不能继续执行。

      第三步,修改动态链接库实现,将b修改为双重指针:

      LIBEXPORT_API char *mySum(char *a,char **b){sprintf((*b),"%s",a); return *b;}
      C#导入定义:

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
      public static extern string mySum (string a, ref string b);
      }
      在C#中调用测试:

      string strDest="";
      string strTmp= RefComm. mySum("45", ref strDest);

      运行查看结果 strTmp 和 strDest 均为"45",调用正确。第三步实现了函数出口参数正确输出结果。

      第四步,修改动态链接库实现,实现整数参数的输出:

      LIBEXPORT_API int mySum(int a,int b,int *c){ *c=a+b; return *c;}
      C#导入的定义:

      public class RefComm
      {
      [DllImport("LibEncrypt.dll",
      EntryPoint=" mySum ",
      CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)]
      public static extern int mySum (int a, int b,ref int c);
      }
      在C#中调用测试:

      int c=0;
      int iSum= RefComm. mySum(,, ref c);

      运行查看结果iSum 和c均为5,调用正确。

      经过以上几个步骤的试验,基本掌握了如何定义动态库函数以及如何在 C# 定义导入,有此基础,很快我实现了变长加密函数在 C# 中的调用,至此目标实现。

      三、结论

      在 C# 中调用 C++ 编写的动态链接库函数,如果需要出口参数输出,则需要使用指针,对于字符串,则需要使用双重指针,对于 C# 的导入定义,则需要使用引用(ref)定义。

      对于函数返回值,C# 导入定义和 C++ 动态库函数声明定义需要保持一致,否则会出现函数调用失败。定义导入时,一定注意 CharSet 和 CallingConvention 参数,否则导致调用失败或结果异常。运行时,动态链接库放在 C# 程序的目录下即可,我这里是一个 C# 的动态链接库,两个动态链接库就在同一个目录下运行。

      回复:

      1、gcc、g++在执行编译的步骤为:
      a.预处理,生成.i的文件[预处理器cpp]
      b.将预处理后的文件转换成汇编语言,生成文件.s[编译器egcs]
      c.将汇编转(.s文件)生成目标代码(机器代码)生成.o的文件[汇编器as]
      d.连接目标代码(.o文件)生成可执行程序[链接器ld]
      2、常有参数说明
      -c
        只激活预处理,编译,和汇编,也就是他只把程序做成obj文件
        例子用法:
        gcc -c hello.c
        他将生成.o的obj文件
      -S
        只激活预处理和编译,就是指把文件编译成为汇编代码。
        例子用法
        gcc -S hello.c
        他将生成.s的汇编代码,你可以用文本编辑器察看

      回复:

      1、 .so动态库的生成 可使用gcc或者g++编译器生成动态库文件(此处以g++编译器为例) g++ -shared -fPIC -c XXX.cpp g++ -shared -fPIC -o XXX....

      回复:

      1、 .so动态库的生成 可使用gcc或者g++编译器生成动态库文件(此处以g++编译器为例) g++ -shared -fPIC -c XXX.cpp g++ -shared -fPIC -o XXX.so XXX.o 2、 .so动态库的动态调用接口函数说明 动态库的调用关系可以在需要调用动态库的程序编译时,...

      回复:

      但是静态一维数组是编译器分配的,对于一些情况可以检查下标是否越界但是动态一维数组是运行时操作系统直接分配的,编译器不会检查下标越界的情况。两种方式都很常见。如果已经确定下标的情况(存储空间大小已定),直接用静态就可以,比如用于...

      回复:

      Device_Init Query_UsrSum 这两个函数在哪个文件里? 库函数? 如果不是库函数而且不在main.c中的话,需要在编译的时候加上这两个函数所在的文件。

      回复:

      楼下是正解, 比如有两个共享库liba.so, libb.so, 位于/lib/下, 用g++ 链接时应该是这样子: g++ -L /lib/ -la -lb hello.cpp -o hello

      回复:

      1、gcc、g++在执行编译的步骤为: a.预处理,生成.i的文件[预处理器cpp] b.将预处理后的文件转换成汇编语言,生成文件.s[编译器egcs] c.将汇编转(.s文件)生成目标代码(机器代码)生成.o的文件[汇编器as] d.连接目标代码(.o文件)生成可执行程序[...

      回复:

      你是不是在编译静态库或者动态库?也就是没有main函数。如果是,再参考一下下边的提示。 -c 参数表示将源文件编译成object(目标文件)。 即 gcc -c foo.c 会编译成 foo.o gcc 不加参数时会编译且尝试链接成可执行文件,然而 foo.c 的代码中没有ma...

      回复:

      第一步,我先从简单的调用出发,定义了一个简单的函数,该函数仅仅实现一个整数加法求和: LIBEXPORT_API int mySum(int a,int b){ return a+b;} C# 导入定义: public class RefComm { [DllImport("LibEncrypt.dll", EntryPoint=" mySum ", Cha...

        上一篇:沃尔沃XC90座椅通风怎么改 下一篇:合肥九重景装饰公司的设计团队好不好?擅长什么风格设计?

        返回主页:启闭阀

        本文网址:http://qibifa.cn/view-208126-1.html
        信息删除