如何安全地将变量的值传递给 C++ 方法,该方法只会将 void* 作为参数?

How can I safely pass a value of a variable to a C++ method, which would only take a void* as an argument?

我有一个函数将 void* 作为唯一参数,并返回 void*gpioThreadFunc_t

我现在有一个 track_t 类型的变量,它基本上是一个 unsigned char,我想用它的值 (!) 作为参数调用我的方法。反过来,该方法必须确保参数确实是 track_t(resp. unsigned char)并使用它。

我试过这样调用方法:

start_thread (Loop, (void *) &track);

…其中 Loop 是方法的名称,track 是相关的(局部)变量。将其值设置为 2 时,该方法得到的是 0 或 131 或其他值,但不是 2。

Loop 定义如下:

void *Loop (void *params);

有人知道我如何调用我的方法并安全地传递必要的参数吗?或者我应该忘记参数传递并改为依赖全局(或实例)变量?谢谢。

澄清:我仍在编写我的代码,因此这不是调试请求。我问这个问题只是为了不 运行 掉入陷阱。

Does anybody know how I can call my method and pass the necessary argument

I tried to call the method like this:

start_thread (Loop, (void *) &track);

假设 Loop 将 void 指针转换回 track_t* 并假设指向的 track 对象在不再使用之前保持活动状态,您尝试的方法将起作用。

虽然在您的示例中强制转换为 void* 是不必要的,因为所有对象指针都隐式转换为 void*.


How can I safely pass a ... void*

无法使接受 void* 的函数安全。它本质上是类型不安全的。

您可以做的是编写一个类型安全的包装器模板,这样就不必直接调用 start_thread。示例:

template<class T>
using fun_t = T*(T*);

template<auto fun_ptr, class T>
void start_thread_safer(T* params)
{
    auto callback = [](void* vparams) -> void* {
        return fun_ptr(static_cast<T*>(vparams));
    };
    start_thread(callback, params);
}

现在您可以安全地使用:

track_t* Loop (track_t* params);
start_thread_safer<Loop>(&track);

有一种优化可以避免间接寻址:由于 unsigned char 保证适合 void* 的内存,您可以直接传递该内存中的对象。对于整数(例如 unsigned char),这很简单:

str::uintptr_t temp = track;
start_thread (Loop, reinterpret_cast<void*>(temp));

// in Loop
track_t track = reinterpret_cast<str::uintptr_t>(params);

如果传递的类型不是整数,但可以简单地复制并适合指针,则以下也适用:

void* params = nullptr;
static_assert(sizeof params >= sizeof track);
std::memcpy(&params, &track, sizeof track);
start_thread (Loop, params);

// in Loop
track_t track;
std::memcpy(&track, &params, sizeof track); 

此优化还提高了安全性,因为不再有任何间接寻址,因此您不会再无法保持指向的参数处于活动状态直到它被使用。

我将把它作为结合这些方法的练习。

除非线程实际上需要访问 track 变量本身(对其进行更改),否则您应该只传递 value 的 [=12] =] 变量而不是其 地址 unsigned charvalue 很容易放入 void* 指针的位中:

void* Loop(void *params) {
    track_t track = static_cast<track_t>(reinterpret_cast<uintptr_t>(params));
    ...
}

...

track_t track = 2;
start_thread(Loop, reinterpret_cast<void*>(static_cast<uintptr_t>(track)));

否则,你可以动态分配一个track_t传给线程,然后在线程退出前释放它:

void* Loop(void *params) {
    std::unique_ptr<track_t> track(static_cast<track_t*>(params));
    ...
}

...

std::unique_ptr<track_t> track(new track_t(2));
if (start_thread(Loop, track.get()))
    track.release();