3

我正在将一个小型 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 提供了一个方便的 typeof 扩展。也许我可以用 void* 做到这一点?如果是这样怎么办?

我到目前为止是这样的:

#define AtomicLoadAcquire(addr)                                       \
    ({ typeof (addr) v = *(volatile typeof (addr) *)(addr); CpuReadWriteFence(); })

但是,这不允许我这样做:

int x = AtomicStoreRelease(&bla);

我将如何解决这个问题?

4

4 回答 4

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);
于 2011-12-07T10:26:40.093 回答
3

你几乎做对了。GCC “表达式中的语句和声明”扩展不必返回 void。

复合语句中的最后一件事应该是一个后跟分号的表达式;此子表达式的值用作整个构造的值。(如果在大括号中最后使用某种其他类型的语句,则该构造的类型为 void,因此实际上没有任何值。)

因此,您可以将宏定义为:

#define AtomicLoadAcquire(addr)                                       \
({ typeof (*addr) v = *(volatile typeof (addr) )(addr); CpuReadWriteFence(); v; })

注意v;宏末尾的。这就是魔法的来源。

另请注意,第一个typeof作为*addr参数,之后没有星号volatile typeof(addr)。这些是与您的主要问题无关的一些小错误。

于 2011-12-07T10:48:31.000 回答
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)开头的“”,恕我直言,这样会更安全。

于 2011-12-07T10:29:33.073 回答
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);
于 2011-12-07T10:35:10.180 回答