Macro that expand differently depending on the function calling it.

F

Fabrice

Hi,

Lets say I want to define a generic macro to swap bytes in a integer:
#define swapbytes(x) ...
I have several implementation of the macros, one is generic C, the
other one will be an optimized assembly version for a specific
architecture.

So I do something like that in swapbytes.h:

#ifdef __SOME_IMPLEMENTATION_SPECIFIC_MACRO__
#define swapbytes(x) \
... some implementation defined assembly crap...
#else
#define swapbytes(x) \
... some generic C code ...
#endif

This works well and I can extend this to support many different
implementation dependent optimizations: MIPS, ARM, x86,...

Now i have an additional issue. In some case, I have two functions in
the same source files that requires two different implementations of
the macro. An example of such case is when you deal with arm thumb or
mips16 instruction set. Some implementation allows you to mix both
types of code, but my swapbytes macro would needs to be different for
both of them.

Is there any way to handle that while still keeping a generic include
file ?

Thanks

-- Fabrice

PS: If you think this is off-topic because I mention mips16 and thumb,
dont even bother replying.I think the C standard was designed to cope
with implementation specific extensions and issues like this.
 
J

Jack Klein

Hi,

Lets say I want to define a generic macro to swap bytes in a integer:
#define swapbytes(x) ...
I have several implementation of the macros, one is generic C, the
other one will be an optimized assembly version for a specific
architecture.

So I do something like that in swapbytes.h:

#ifdef __SOME_IMPLEMENTATION_SPECIFIC_MACRO__
#define swapbytes(x) \
... some implementation defined assembly crap...
#else
#define swapbytes(x) \
... some generic C code ...
#endif

This works well and I can extend this to support many different
implementation dependent optimizations: MIPS, ARM, x86,...

Now i have an additional issue. In some case, I have two functions in
the same source files that requires two different implementations of
the macro. An example of such case is when you deal with arm thumb or
mips16 instruction set. Some implementation allows you to mix both
types of code, but my swapbytes macro would needs to be different for
both of them.

Is there any way to handle that while still keeping a generic include
file ?

Thanks

-- Fabrice

PS: If you think this is off-topic because I mention mips16 and thumb,
dont even bother replying.I think the C standard was designed to cope
with implementation specific extensions and issues like this.

If you can provide proof from an Internationally recognized court of
law that has granted you supreme dictatorial powers over comp.lang.c,
and furthermore provide proof of that court's legal jurisdiction in
doing so, then you might attempt to forbid people who might dislike
your off-topic question from replying.

But I doubt if that would stop them. It certainly wouldn't stop me.

As for your incorrect belief about the C standard, and it is
incorrect, who gives a piece of bovine excrement?

*plonk*

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
I

Ian Collins

Fabrice said:
Hi,

Lets say I want to define a generic macro to swap bytes in a integer:
#define swapbytes(x) ...
I have several implementation of the macros, one is generic C, the
other one will be an optimized assembly version for a specific
architecture.

So I do something like that in swapbytes.h:

#ifdef __SOME_IMPLEMENTATION_SPECIFIC_MACRO__
#define swapbytes(x) \
... some implementation defined assembly crap...
#else
#define swapbytes(x) \
... some generic C code ...
#endif

This works well and I can extend this to support many different
implementation dependent optimizations: MIPS, ARM, x86,...

Now i have an additional issue. In some case, I have two functions in
the same source files that requires two different implementations of
the macro. An example of such case is when you deal with arm thumb or
mips16 instruction set. Some implementation allows you to mix both
types of code, but my swapbytes macro would needs to be different for
both of them.
Why not just uses another macro, or better still, functions?
 
P

Peter Nilsson

Fabrice said:
Lets say I want to define a generic macro to swap bytes
in a integer:
#define swapbytes(x) ...
I have several implementation of the macros, one is
generic C, the other one will be an optimized assembly
version for a specific architecture.

So I do something like that in swapbytes.h:

#ifdef __SOME_IMPLEMENTATION_SPECIFIC_MACRO__
#define swapbytes(x) \
... some implementation defined assembly crap...
#else
#define swapbytes(x) \
... some generic C code ...
#endif

This works well and I can extend this to support many
different implementation dependent optimizations: MIPS,
ARM, x86,...

Now i have an additional issue. In some case, I have two
functions in the same source files that requires two
different implementations of the macro.

So use two macros.

#define swapbytes_special(a,b) ...

#if blah
#define swapbytes(a,b) swapbytes_special(a,b)
#elif ...
#define swapbytes(a,b) ...
#elif ...
#define swapbytes(a,b) ...
....
#endif

void foo() { ...swapbytes_special(a,b); ... }
void bar() { ...swapbytes(a,b); ...}

PS: If you think this is off-topic because I mention
mips16 and thumb, dont even bother replying.

If it's off topic, don't bother posting. That way,
everyone wins.
I think the C standard was designed to cope with
implementation specific extensions and issues like
this.

Of course it is. But that doesn't mean that comp.lang.c
is the place to discus those extensions.
 
A

Ark Khasin

Fabrice said:
Hi,

Lets say I want to define a generic macro to swap bytes in a integer:
#define swapbytes(x) ...
I have several implementation of the macros, one is generic C, the
other one will be an optimized assembly version for a specific
architecture.

So I do something like that in swapbytes.h:

#ifdef __SOME_IMPLEMENTATION_SPECIFIC_MACRO__
#define swapbytes(x) \
... some implementation defined assembly crap...
#else
#define swapbytes(x) \
... some generic C code ...
#endif

This works well and I can extend this to support many different
implementation dependent optimizations: MIPS, ARM, x86,...

Now i have an additional issue. In some case, I have two functions in
the same source files that requires two different implementations of
the macro. An example of such case is when you deal with arm thumb or
mips16 instruction set. Some implementation allows you to mix both
types of code, but my swapbytes macro would needs to be different for
both of them.

Is there any way to handle that while still keeping a generic include
file ?

Thanks

-- Fabrice

PS: If you think this is off-topic because I mention mips16 and thumb,
dont even bother replying.I think the C standard was designed to cope
with implementation specific extensions and issues like this.
#define swap(a,b) ((a)^=(b)^=(a)^=(b))
Doesn't get much simpler than that. Why do you need platform-specific
hoop-jumping?
 
P

pete

Ark said:
#define swap(a,b) ((a)^=(b)^=(a)^=(b))
Doesn't get much simpler than that.

That expression is no good.

N869
6.5 Expressions
[#2] Between the previous and next sequence point an object
shall have its stored value modified at most once by the
evaluation of an expression.
 
B

Ben Pfaff

Ark Khasin said:
#define swap(a,b) ((a)^=(b)^=(a)^=(b))

Please read the FAQ.

3.3b: Here's a slick expression:

a ^= b ^= a ^= b

It swaps a and b without using a temporary.

A: Not portably, it doesn't. It attempts to modify the variable a
twice between sequence points, so its behavior is undefined.

For example, it has been reported that when given the code

int a = 123, b = 7654;
a ^= b ^= a ^= b;

the SCO Optimizing C compiler (icc) sets b to 123 and a to 0.

See also questions 3.1, 3.8, 10.3, and 20.15c.

(I don't endorse using products from SCO.)
 
A

Ark Khasin

Ben said:
Please read the FAQ.

3.3b: Here's a slick expression:

a ^= b ^= a ^= b

It swaps a and b without using a temporary.

A: Not portably, it doesn't. It attempts to modify the variable a
twice between sequence points, so its behavior is undefined.

For example, it has been reported that when given the code

int a = 123, b = 7654;
a ^= b ^= a ^= b;

the SCO Optimizing C compiler (icc) sets b to 123 and a to 0.

See also questions 3.1, 3.8, 10.3, and 20.15c.

(I don't endorse using products from SCO.)
OK. Got things wrong again. How about
#define swap(a,b) do{(a)^=(b); (b)^=(a); (a)^=(b);}while(0)
?
But all in all, I agree with FAQ 10.3: "If you're consumed by a
passionate desire to solve this problem once and for all, please
reconsider; there are better problems worthier of your energies."
 
S

SM Ryan

# OK. Got things wrong again. How about
# #define swap(a,b) do{(a)^=(b); (b)^=(a); (a)^=(b);}while(0)

Assume for example, that variable a is loaded in register R1, and
b in R2. On optimising compiler can potentially translate:

t = a; a = b; b = t;

into the assembly code:

No code at all, it simply relabels register R2 as a and R1 as b.
An optimiser could possibly realizes the exclusive ors are a swap,
or it might not, with three operations to do what it might have done
with zero operations if the intent of the programmer was clear.

# But all in all, I agree with FAQ 10.3: "If you're consumed by a
# passionate desire to solve this problem once and for all, please
# reconsider; there are better problems worthier of your energies."

Let the optimiser worry about cleverness. Write code that is obvious.
 
C

CBFalconer

Ark said:
.... snip ...

OK. Got things wrong again. How about
#define swap(a,b) do{(a)^=(b); (b)^=(a); (a)^=(b);}while(0)
?
But all in all, I agree with FAQ 10.3: "If you're consumed by a
passionate desire to solve this problem once and for all, please
reconsider; there are better problems worthier of your energies."

Fails. Try:

int a = 5;
swap(a, a);

results in a == 0
 
A

Ark Khasin

CBFalconer said:
Ark Khasin wrote:
... snip ...

Fails. Try:

int a = 5;
swap(a, a);

results in a == 0
Arrgh! Which proves stealing is not good. Does FAQ 10.3 "If the values
are integers, a well-known trick using exclusive-OR could perhaps be
used" need revising?
 
R

Richard Heathfield

Ark Khasin said:
Arrgh! Which proves stealing is not good. Does FAQ 10.3 "If the values
are integers, a well-known trick using exclusive-OR could perhaps be
used" need revising?

No, you just need to read it more carefully next time. It actually *tells*
you that the XOR "trick" doesn't work, in the very sentence you quote,
which reads in full as follows:

"If the values are integers, a well-known trick using exclusive-OR could
perhaps be used, but it will not work for floating-point values or
pointers, or if the two values are the same variable."

The whole thrust of FAQ 10.3 is "please don't do this stupid thing", and
anyone taking about 40% of *one* sentence of the reply out of context and
using it to justify or excuse broken code is guilty of reading with their
brain switched off.
 
K

Keith Thompson

Ark Khasin said:
OK. Got things wrong again. How about
#define swap(a,b) do{(a)^=(b); (b)^=(a); (a)^=(b);}while(0)
?
[...]

Better, but still not good.

The "do { ... } while(0)" trick isn't needed in this case, since
everything in the expansion is just an expression (or would be if you
dropped the semicolons). You could just write:

#define swap(a,b) ((a)^=(b), (b)^=(a), (a)^=(b))

or, preferably:

#define SWAP(a,b) ((a)^=(b), (b)^=(a), (a)^=(b))

That does address the sequence-point issue.

But try using to swap floating-point variables. And it quietly fails
if you try to swap a variable with itself, something that could happen
accidentally if you do something like SWAP(array, array[j]) or
SWAP(*p1, *p2). Finally, it's not inconceivable that xor'ing two
signed integer values could do odd things on some systems (bitwise
operations on signed integers make me nervous).

The way to swap two variables is to use a temporary:

tmp = x;
x = y;
y = tmp;

This is simple enough that it's probably not worth the effort to
encapsulate it. Just write the three assignments where you need them.

(It would be nice if C allowed multiple values to be assigned, so you
could write something like ``(x, y) = (y, x)'', but it doesn't.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,996
Messages
2,570,237
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top