提问人:t1m013y 提问时间:11/5/2023 最后编辑:273Kt1m013y 更新时间:11/5/2023 访问量:96
如何将易失性 typedef 结构转换为非易失性 typedef 结构作为函数的参数
How to cast volatile typedef struct to non-volatile typedef struct as argument of the function
问:
我正在为 STM32 编写一个 C 库,遇到了一个问题。
我有typedef结构:
typedef struct foo {
// some struct elements
} foo;
类型为:foo
volatile foo bar;
带有 -typed 参数的函数:foo
int foobar(foo* baz) {
// some operations with baz
return 0;
}
当我尝试调用时,出现错误:foobar(&bar);
error: invalid conversion from ‘volatile foo*’ to ‘foo*’ [-fpermissive]
如果我投射到 () 会起作用吗?volatile foo*
foo*
foobar((foo*)&bar);
我试图投射到,但我不知道它是否可以在没有错误的情况下工作。volatile foo*
foo*
答:
注意:在我创建答案后,标签 C++ 已被删除。
您可以使用模板函数解决此问题,std::enable_it_t 是一个额外的 (SFINAE) 检查,以避免接受除 foo_t 以外的任何内容。 注意:我使用refences而不是指针,因为我希望输入是一个有效的实例(使用指针,你总是必须做额外的nullptr检查)
#include <type_traits>
#include <iostream>
/*typedef*/ struct foo_t // <== typedef is "C" syntax, not needed
{
};
// any form of foo_t is ok (with or without const, volatile or reference)
template<typename type_t>
constexpr bool is_foo_t()
{
return std::is_same_v<foo_t,std::remove_cvref_t<type_t>>;
}
template<typename type_t>
auto foobar(const type_t& foo) -> std::enable_if_t<is_foo_t<type_t>(),int>
{
// reusable code here
// just a demo to show both arguments are accepted
if constexpr(std::is_volatile_v<type_t>)
{
std::cout << "Called with volatile foo_t\n";
}
else
{
std::cout << "Called with non-volatile foo_t\n";
}
return 0;
}
int main()
{
volatile foo_t volatile_foo;
foobar(volatile_foo);
foo_t foo;
foobar(foo);
}
评论
它不仅是铸造的。如果需要以这种方式强制转换,则意味着代码有问题。
如果要使用不对对象进行参数的函数,则意味着需要将此对象视为不容易产生副作用。函数不必假设编译器不可见的内容可以更改它并应用对象无法实现的优化。最重要的是,对对象的所有访问都必须应用于其永久存储位置。volatile
volatile
volatile
volatile
如果您有此问题,则:
你过度使用关键字,你的对象不一定是(因为你想把它用作非)。您应该重新考虑您的程序数据类型。
volatile
volatile
volatile
volatile
您可以将函数声明为 take - 但它会阻止许多可能的优化。
volatile
您可以有不同的函数处理和非数据。
volatile
volatile
如果我将易失性 foo* 转换为 foo* ( foobar((foo*)&bar);),它会起作用吗?
不。它只会使警告静音,但它可能非常危险。
struct x
{
bool dangerous;
float data;
};
int dangerous(struct x *ptr)
{
if(!ptr -> dangerous)
{
/* do something */
if(!ptr -> dangerous) never_call_if_dangerous_is_true();
}
}
int dangerous_volatile(volatile struct x *ptr)
{
if(!ptr -> dangerous)
{
/* do something */
if(!ptr -> dangerous) never_call_if_dangerous_is_true();
}
}
以及生成的代码:
dangerous:
cmp BYTE PTR [rdi], 0
jne .L2
xor eax, eax
jmp never_call_if_dangerous_is_true
.L2:
ret
dangerous_volatile:
mov al, BYTE PTR [rdi]
test al, al
jne .L5
mov al, BYTE PTR [rdi]
test al, al
jne .L5
jmp never_call_if_dangerous_is_true
.L5:
ret
在非易失性版本中,跳过第二次检查。如果某些东西(信号、中断)改变了成员,它将调用该函数 - 例如杀死某人dangerous
评论
volatile
never_call_if_dangerous_is_true()
评论
volatile foo *baz
volatile
volatile
foo
template