昨天我正在研究共享对象的动态加载和获取函数指针。
我多次被告知,通过 void 指针共享指向函数的指针是 ISO C++ 标准禁止的,并且仍然是一个有待解决的问题。
看完Johan Petterson’s artitle “about the problem with dlsym”我更明白其中的原因,我也明白被标准禁止并不意味着你绝对不能使用它。否则,所有 C++ 程序员如何使用正确的 ISO C++ 代码使用来自共享对象的函数?只是猜测,我可能是错的,我不是 C++ 专家。
在试验我的代码时,我发现通过共享指向包含对我要调用的函数的引用的结构的指针,我的编译器不会报错。我在编译时使用 -Wall 和 -pedantic。
我的代码如下所示:
myclass.hpp
class myclass
{
public:
virtual void dosomething (void)=0;
}
api.hpp
#include <myclass.hpp>
struct API
{
myclass* (* func)(void);
};
so.hpp
#include <iostream>
#include "myclass.cpp"
#include "api.hpp"
class childclass : public myclass
{
void dosomething (void)
{
std::cout << "Did it.\n";
}
}
/* function to return a new instance of childclass */
extern "C" myclass* make (void)
{
return new childclass;
}
/* struct that contains a pointer to the function */
extern "C" API interface;
API interface
{
make
};
host.cpp
#include <iostream>
#include <dlfcn.h>
#include "myclass.hpp"
#include "api.hpp"
int main (void)
{
void * th = dlopen("./so.so", RTLD_LAZY);
/* error checking was here */
#ifndef usefunction
API* api = static_cast<API*>( dlsym(th, "interface") );
myclass * inst = api->make();
inst->dosomething();
#else
myclass* (*func)(void) = reinterpret_cast<myclass* (*)(void)>( dlsym(th, "make") );
/* will never get to this point */
#endif
return 0;
}
已经编译了 so.so,然后我编译了我的 host.cpp 文件。
g++ -ldl -Wall -pedantic host.cpp -o host
编译正常,程序正确打印 Did it. 运行时。
g++ -ldl -Wall -pedantic host.cpp -o host -Dusefunction
提示
In function ‘int main(int, char**)’:
warning: ISO C++ forbids casting between pointer-to-function
and pointer-to-object [enabled by default]
我知道这只是一个警告,但为什么在第一种情况下不打印警告,当使用结构时,如果最终我能够间接引用指向驻留在共享对象中的函数的指针?
说到这里,有人知道以完全正确的 ISO C++ 方式实现所有这些的方法吗?它甚至存在吗?
最佳答案
完全符合标准的解决方案:
extern "C" typedef int (func_t)(char, double); // desired API function signature
int main()
{
static_assert(sizeof(void *) == sizeof(func_t *), "pointer cast impossible");
void * p = dlsym(handle, "magic_function");
char const * cp = reinterpret_cast<char const *>(&p);
func_t * fp;
std::copy(cp, cp + sizeof p, reinterpret_cast<char *>(&fp));
return fp('a', 1.25);
}
一种更简单但更可疑的写法,使用了一些类型双关语:
static_assert(sizeof(void *) == sizeof(func_t *), "pointer cast impossible");
void * vp = dlsym(handle, "magic_function");
func_t * fp;
*reinterpret_cast<void **>(&fp) = vp; // this is type-punning
关于c++ - 当我将 void 指针导入到具有指向共享对象中函数的指针的结构时,我没有收到警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12585030/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我试图使用yard记录一些Ruby代码,尽管我所做的正是所描述的here或here#@param[Integer]thenumberoftrials(>=0)#@param[Float]successprobabilityineachtrialdefinitialize(n,p)#initialize...end虽然我仍然得到这个奇怪的错误@paramtaghasunknownparametername:the@paramtaghasunknownparametername:success然后生成的html看起来很奇怪。我称yard为:$yarddoc-mmarkdown我做错了什么?
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re