【问题标题】:Use of shared library is good in c but same code is bad in c++?共享库的使用在 c 中很好,但在 c++ 中相同的代码不好?
【发布时间】:2016-01-09 05:41:23
【问题描述】:

您好,我对共享库有一些疑问。我在下面的共享库上在线教程是代码。请帮助我理解,非常感谢。

ctest1.c

void ctest1(int *i)
    {
       printf("I am in shared library");
       *i=100;
     }

ctest1.h

#ifndef CTEST_H
#define CTEST_H

#ifdef __cplusplus
extern "C" {
#endif

void ctest1(int *);
#ifdef __cplusplus
}
#endif

#endif

mytry.c

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include "ctest1.h"

int main(int argc, char **argv)
{
   void *lib_handle;
   double (*fn)(int *);
   int x=990;
   char *error;

   lib_handle = dlopen("libmylibrary.so", RTLD_LAZY);  // opening the shared library
   if (!lib_handle)
   {
      fprintf(stderr, "%s\n", dlerror());
      exit(1);
   }

 fn = dlsym(lib_handle, "ctest1");  //storing the address of shared library function
   if ((error = dlerror()) != NULL)
   {
      fprintf(stderr, "%s\n", error);
      exit(1);
   }


   fn(&x);
   printf("Valx=%d\n",x);

   dlclose(lib_handle);
   return 0;
}

第 1 步:使用 -c 选项创建一个目标文件 gcc -c 我的 ctest1.c

第 2 步:使用 -shared 选项创建共享库 gcc -shared -libmylibrary.so ctest1.c

第 3 步:编译我的主要源代码,即 mytry.c gcc -rdynamic -o run mytry.c -ldl

第 4 步: ./run

上面的代码一切顺利,但我有一些疑问,请帮助我理解。下面是列表。

  1. 为什么函数指针,即 fn 返回类型是双精度的,虽然它保存的是 dlsym 返回的地址,即 void *?

  2. 如果我使用以下命令在 c++ 中尝试相同的代码

    g++ -rdynamic -o run mytry.cc -ldl

    为什么我会收到错误,因为 从 void * 到 double() (int) 的转换无效我该如何解决?

    fn = dlsym(lib_handle, "ctest1"); //存储共享库函数的地址这是我在c++中尝试时出错的地方

【问题讨论】:

  • 哪一行产生了错误?
  • fn = dlsym(lib_handle, "ctest1"); //存储共享库函数的地址。如果我在 cpp 中尝试,这是 mytry.c 中的行

标签: c++ c shared-libraries


【解决方案1】:

C++ 的类型比 C 更强,因此 void* 类型的指针不会自动转换为另一种类型的指针。因此,如果dlsym 返回void*,则在将结果存储在fn 中时,您必须将结果显式转换为C++,它的类型为double(*)(int*)

但是,如果 不是 类型为 double(*)(int*),则您的函数 ctest1。把它转换成那个是不安全的。您需要将fn 的类型更改为void(*)(int*)。否则转换是不安全的。

void* 转换为函数指针的语法非常难看:

fn = (void(*)(int*))dlsym(lib_handle, "ctest1");

所以最好只使用typedef

typedef void (*ctestptr)(int*);
ctestptr fn = (ctestptr)dlsym(lib_handle, "ctest1");

【讨论】:

  • 我厌倦了 valgrind 我找不到任何错误你能说一下它是多么不安全 下面是 valgrind 输出 ==4854== ==4854== HEAP 摘要:==4854 == 在退出时使用:0 个块中的 0 个字节 ==4854== 总堆使用量:5 个分配,5 个释放,796 个字节分配 ==4854== ==4854== 所有堆块都被释放 - 没有泄漏可能 ==4854== ==4854== 对于检测到和抑制的错误计数,重新运行:-v ==4854== 错误摘要:0 个上下文中的 0 个错误(抑制:0 个来自 0)
  • @user3588044 从void* 转换为函数指针让我感到紧张,因为有很大机会将未定义的行为引入代码,其中可能发生任何数量的事情。但是,如果dlsym 的返回返回一个指向函数的指针,该函数的返回类型为double 和一个类型为int 的参数,那么这是一个非常安全的转换。
  • @user3588044 我刚刚重读了您的问题并意识到fn 不是您的函数ctest1 的正确类型。我编辑了我的答案。
  • 感谢最后一个疑问,为什么我需要将函数指针返回类型仅作为双精度类型,在这里真的很困惑,为什么不使用其他类型?函数指针的返回类型不应该与它所持有的函数地址相同吗?
  • @user3588044 您需要将函数指针的类型更改为void(*fn)(int*)。这是错误的。
【解决方案2】:

c 代码不支持多态性,因此仅按名称搜索函数。 但是在c++中你可以有几个同名的函数,所以必须检查类型。

问题是,当你返回 void 并像 double 一样威胁它时,你认为应该发生什么?

你真正应该做什么:

typedef void (*fnptr)(int *); //create a typedef for easy casting.
fnptr fn = (fnptr)dlsym(lib_handle, "ctest1");//cast dlsym return value.

注意函数指针的签名与函数签名相同。

【讨论】:

  • 多态性无关紧要。你的意思是超载吗?
  • @SHR 谢谢你能说一下为什么上面mytry.c中的函数指针即fn返回类型是double而不是void?虽然它持有 dlsym 返回的地址,但它是 void * ?
  • @user3588044 默认返回类型是void*,这就是dlsym 返回void* 的原因,但它返回一个指向函数的指针,你应该正确地转换它,除非你想破坏堆栈。为什么你的代码中的返回类型是double,而你的函数是void?对我来说它看起来像一个错误,也许它被改变并被遗忘了..
  • @CaptainGiraffe 确实,超载。
猜你喜欢
  • 1970-01-01
  • 2014-04-29
  • 1970-01-01
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多