Как я могу преобразовать эту шаблонную функцию c ++ в альтернативу C? - PullRequest
3 голосов
/ 07 декабря 2011

Я конвертирую части небольшой библиотеки 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 ]

4 голосов
/ 07 декабря 2011

Вы не можете вернуть значение с помощью макроса. Попробуйте это:

#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);
3 голосов
/ 07 декабря 2011

Вы почти правильно поняли.Расширение GCC «операторы и объявления в выражениях» не должно возвращать void.

Последним в составном операторе должно быть выражение, за которым следует точка с запятой;значение этого подвыражения служит значением всей конструкции.(Если вы используете какой-то другой вид оператора последним в фигурных скобках, конструкция имеет тип void и, следовательно, фактически не имеет значения.)

Так что вы можете определить свой макрос как:

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

Обратите внимание на v; в конце макроса.Вот откуда приходит магия.

Также обратите внимание, что первый typeof принимает *addr в качестве аргумента, и после volatile typeof(addr) звезды нет.Это были незначительные ошибки, не связанные с вашей главной проблемой.

0 голосов
/ 07 декабря 2011

Передача типа в макросе, вероятно, лучшее, что вы можете сделать:

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);
0 голосов
/ 07 декабря 2011

Можете ли вы добавить возвращаемое значение в качестве параметра макроса? Примерно так:

#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)» в начале, что будет безопаснее, ИМХО.

...