如何将此c ++模板函数转换为C替代?

时间:2011-12-07 10:10:10

标签: c++ c templates gcc equivalent

我正在将一个小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);

我如何解决这个问题?

4 个答案:

答案 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);