【问题标题】:How to generate function in runtime?如何在运行时生成函数?
【发布时间】:2016-08-06 00:11:39
【问题描述】:

我正在尝试用 C++ 编写中断服务程序,这里有一些代码 sn-p

void handlerProxy(int intrNo) {}

typedef void(*IntrHandler)();

IntrHandler IDT[256];

我想像这样在运行时或编译时初始化IDT

for (size_t i = 0; i < 256; ++i) {
    // It doesn't compile
    IDT[i] = std::bind(handlerProxy, i);
    // or
    IDT[i] = [i] () {handlerProxy(i);};
}

问题是

  • 带捕获的 lambda 函数无法转换为函数指针
  • 我的代码会用-fno-rtti编译,所以std::function::target不可用

有没有可能我可以做到这一点? 我不想手动编写IDT[0]= ... IDT[1]=... 或使用其他程序来生成它。允许使用宏和内联汇编。 IDT 的类型可以改变,但是IDT 的元素应该是函数地址,这意味着像jmp IDT[0] 这样的东西应该是有效的。

【问题讨论】:

  • IDT[] 的类型设为sturct 与函数调用运算符重载(函数对象)是不可能的吗?
  • @Galik 在这种情况下jmp IDT[0] 将不起作用。 BIOS 仅通过push 寄存器和标志以及jmp 地址调用这些函数

标签: c++ macros operating-system c++14


【解决方案1】:

您可以像这样将intrNo 设为模板参数:

template <int intrNo>
void handlerProxy() {}

typedef void(*IntrHandler)();

并使用包扩展初始化数组:

template <typename IS>
struct helper;

template <size_t ... Is>
struct helper<std::index_sequence<Is...>> {
  static constexpr std::array<IntrHandler, sizeof...(Is)> make_handlers() {
    return {{ &handler_proxy<Is> ... }};
  }
};

constexpr std::array<IntrHandler, 256> IntrHandlers = helper<std::make_index_sequence<256>>::make_handlers();

IntrHandler * IDT = IntrHandlers.data();

(警告购买者,代码未测试)

【讨论】:

  • 可以,虽然IntrHandlers.data()不能直接分配给IntrHandler *——只需要稍作修改。
【解决方案2】:

Chris 的回答更简洁,不过这可以用元组来完成,将 handlerProxy 定义为带有静态成员的模板化函数对象:

template <int i>
    struct handlerProxy{
    static int func(){return i * i;}
};

然后函数创建指向函数的元组:

template <size_t... I>
decltype(auto) functions(std::index_sequence<I...>) {
         return return std::make_tuple(&handlerProxy<I>::func...);
}
template <size_t size>
decltype(auto) generate_functions() {                                                      
   using Indices = std::make_index_sequence<size>;
   return functions(Indices{});
}

使用:

int main()
{
    //generate tuple of functions
    auto IDT = generate_functions<256>();
    //call 2th function
    std::cout << std::get<2>(IDT)();
}

注意:gcc中的-ftemplate-depth选项应该设置为比较大的数字,50000,才能编译

【讨论】:

  • 我认为它行不通。请注意,在我的问题中,我需要像 jmp IDT[0] 这样的东西才能有效。 IDT 中的每个元素都必须是 32 位地址。虽然std::get&lt;2&gt;(IDT)() 可以工作,但调用这些函数的是 BIOS。 BIOS 不知道operator (),BIOS 只知道jmp 的地址而不传递任何参数。
  • 也许我可以使用地址&amp;handlerProxy&lt;0&gt;::operator (),&amp;handlerProxy&lt;1&gt;::operator () ...来填充IDT数组,但我不确定在asm中简单的jmp到这个地址是否总是可以正确调用函数。
  • 我的意思是成员函数总是有一个隐藏参数this,但是BIOS不会传递这个参数所以我不确定它是否会有一些副作用。
  • @Slardar Zhang 我编辑了代码。而不是 operator() 使用静态成员函数
猜你喜欢
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-12
  • 2022-10-02
相关资源
最近更新 更多