我正在将一个小C ++库的部分转换为C(gcc)。在这样做时,我想将以下模板函数转换为宏(为了可读性而删除了注释)。 CpuReadWriteFence()是我成功转换为宏的另一个函数。
template<typename T>
static inline T AtomicLoadAcquire(T const* addr)
{
T v = *const_cast<T const volatile*>(addr);
CpuReadWriteFence();
return v;
}
由于C中没有模板我使用的是函数或宏。 GCC提供了一个 方便的扩展类型。也许我可以用void *做到这一点?如果是这样的话?
到目前为止我所拥有的是:
#define AtomicLoadAcquire(addr) \
({ typeof (addr) v = *(volatile typeof (addr) *)(addr); CpuReadWriteFence(); })
然而,这不允许我这样做:
int x = AtomicStoreRelease(&bla);
我如何解决这个问题?
答案 0 :(得分:4)
您无法使用宏返回值。试试这个:
#define AtomicLoadAcquire(addr, ref) \
({ typeof (addr) v = *(volatile typeof (addr) *)(addr); CpuReadWriteFence(); ref = v; })
int x;
AtomicStoreRelease(&bla, x); // Instead of int x = AtomicStoreRelease(&bla);
答案 1 :(得分:3)
你几乎做对了。 GCC "statements and declarations in expressions"扩展名不必返回void。
复合语句中的最后一件事应该是一个后跟分号的表达式;此子表达式的值用作整个构造的值。 (如果你在大括号中最后使用了一些其他类型的语句,那么构造的类型为void,因此实际上没有值。)
因此,您可以将宏定义为:
#define AtomicLoadAcquire(addr) \
({ typeof (*addr) v = *(volatile typeof (addr) )(addr); CpuReadWriteFence(); v; })
请注意宏末尾的v;
。这就是魔术的来源。
另请注意,第一个typeof
将*addr
作为参数,volatile typeof(addr)
后没有星标。这些是与你的主要问题无关的一些小错误。
答案 2 :(得分:0)
您可以将返回值添加为宏参数吗?这样的事情:
#define AtomicLoadAcquire(addr, ret) \
( typeof (addr) v = *(volatile typeof (addr) *)(addr); CpuReadWriteFence(); )
这很难看,但这会为你做到这一点:
AtomicLoadAcquire(someaddr, x);
翻译为:
/* assuming someaddr is int* */
int x = *(volatile int *)(someaddr); CpuReadWriteFence();
/* now you have x defined */.
这将完全符合您的要求。
其他选项(如miaout17所述)是在调用宏之前声明x
,然后在开头删除“typeof(addr)
”,这样会更安全,恕我直言。
答案 3 :(得分:0)
在宏中传递类型可能是你能做的最好的事情:
static inline const volatile void* AtomicLoadAcquire_f(void const* addr)
{
const volatile void* v = (void const volatile*)addr;
CpuReadWriteFence();
return v;
}
#define AtomicLoadAcquire(type, pointer) \
(*((const volatile type*)AtomicLoadAcquire_f(pointer)))
int x = AtomicLoadAcquire(int, &bla);