我有一个函数,将void*
作为唯一参数,并且还返回void*
:gpioThreadFunc_t
我现在有一个类型为track_t的变量,它基本上是一个unsigned char
,并且想用其值(!)作为参数来调用我的方法。反过来,该方法必须确保该参数确实是track_t
(分别是unsigned char
)并使用它。
我试图这样调用方法:
start_thread (Loop, (void *) &track);
…,其中Loop
是方法的名称,track
是有问题的(本地)变量。将其值设置为2时,该方法获得0或131或其他值,但不是2。
Loop
的定义如下:
void *Loop (void *params);
有人知道如何调用我的方法并安全地传递必要的参数吗?还是应该忘记传递参数,而要依赖全局(或实例)变量?谢谢。
Clarification:我仍在处理我的代码,因此这不是调试请求。我问这个问题只是为了避免陷入陷阱。
除非线程实际上需要访问track
变量本身(以对其进行更改),否则您应该只传递track
变量的value而不是其address。 unsigned char
的value容易适合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();
有人知道我如何调用我的方法并传递必要的参数
我试图这样调用方法:
start_thread (Loop, (void *) &track);
[您尝试过的工作,假设Loop
将void指针转换回track_t*
,并假设所指向的track
对象保持活动状态,直到不再使用为止。
尽管在您的示例中,强制转换为void*
是不必要的,因为所有对象指针都隐式转换为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(¶ms, &track, sizeof track);
start_thread (Loop, params);
// in Loop
track_t track;
std::memcpy(&track, ¶ms, sizeof track);
此优化还提高了安全性,因为不再存在任何间接调用,因此,在使用它之前,您再也不能不使指向性参数保持活动状态。
我将把它作为结合这些方法的练习。
除了雷米·勒博的答案:
安全吗?
创建一个类,将void* Loop(void* params)
设置为其私有静态成员,添加一个调用start_thread(Loop, reinterpret_cast<void*>(static_cast<uintptr_t>(track)))
的公共静态成员(或朋友函数)。>
然后,您可以保证在编译时仅将[C0]作为参数调用Loop()
。