hookenz
hookenz

Reputation: 38907

How can I convert this c++ template function to a C alternative?

I'm converting parts of a small C++ library to C (gcc). In doing so I'm wanting to convert the following template function to a macro (comments removed for readibility). CpuReadWriteFence() is another function that I've converted to a macro successfully.

template<typename T>
static inline T AtomicLoadAcquire(T const* addr)
{
    T v = *const_cast<T const volatile*>(addr);
    CpuReadWriteFence();
    return v;
}

Since there are no templates in C I'm either using functions or macros. GCC provides a convenient typeof extension. Perhaps I could do it with void*? if so how?

What I have so far is this:

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

However, that won't allow me to do this:

int x = AtomicStoreRelease(&bla);

How would I get around this ?

Upvotes: 3

Views: 1552

Answers (4)

CygnusX1
CygnusX1

Reputation: 21778

You almost got it right. The GCC "statements and declarations in expressions" extension does not have to return void.

The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. (If you use some other kind of statement last within the braces, the construct has type void, and thus effectively no value.)

So you can define your macro as:

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

Note the v; at the end of the macro. That's where the magic comes from.

Also note that the first typeof takes *addr as an argument and there is no star after volatile typeof(addr). Those were some minor bugs unrelated to your main problem.

Upvotes: 3

Pubby
Pubby

Reputation: 53047

Passing the type in the macro is probably the best you can do:

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

Upvotes: 0

littleadv
littleadv

Reputation: 20272

Can you add the return value as a macro parameter? Something like that:

#define AtomicLoadAcquire(addr, ret)                                       \
    ( typeof (addr) v = *(volatile typeof (addr) *)(addr); CpuReadWriteFence(); )

It's ugly but this will do this for you:

AtomicLoadAcquire(someaddr, x);

translated to:

/* assuming someaddr is int* */
int x = *(volatile int *)(someaddr); CpuReadWriteFence(); 
/* now you have x defined */.

Which would be exactly as you want it.

Other option (as mentioned by miaout17) is to declare x before calling the macro, and then remove the "typeof(addr)" in the beginning, that would be safer, IMHO.

Upvotes: 0

miaout17
miaout17

Reputation: 4875

You can't return a value with a macro. Try this:

#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);

Upvotes: 4

Related Questions