Velocity Reviews > Function-like macro

# Function-like macro

Russell Shaw
Guest
Posts: n/a

 05-24-2005
Hi,

How do i make an if/then/else macro act as a function
so that the whole thing looks like the return value?

I tried this lame attempt for starters:

#define A_FROM_B(b) \
( \
if(b < 10) { \
a = b; \
} \
else { \
a = 2*b; \
}, \
a; \
)

Richard Bos
Guest
Posts: n/a

 05-24-2005
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:

> How do i make an if/then/else macro act as a function
> so that the whole thing looks like the return value?

You don't. That's what the ?: operator is for.

> I tried this lame attempt for starters:
>
> #define A_FROM_B(b) \
> ( \
> if(b < 10) { \
> a = b; \

a? What is a? What happens if I call this macro in a function where a is
a struct?

> } \
> else { \
> a = 2*b; \
> }, \
> a; \
> )

#define A_FROM_B(b) ((b)<10? (b): 2*(b))

Note the parens around b in the definition of the macro. They will save
your bacon some day when you decide to call A_FROM_B(x+10).

Richard

Russell Shaw
Guest
Posts: n/a

 05-24-2005
Richard Bos wrote:
> Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
>
>>How do i make an if/then/else macro act as a function
>>so that the whole thing looks like the return value?

>
> You don't. That's what the ?: operator is for.
>
>>I tried this lame attempt for starters:
>>
>>#define A_FROM_B(b) \
>> ( \
>> if(b < 10) { \
>> a = b; \

>
> a? What is a? What happens if I call this macro in a function where a is
> a struct?

Like i said, it's a lame one

>> } \
>> else { \
>> a = 2*b; \
>> }, \
>> a; \
>> )

>
> #define A_FROM_B(b) ((b)<10? (b): 2*(b))
>
> Note the parens around b in the definition of the macro. They will save
> your bacon some day when you decide to call A_FROM_B(x+10).
>
> Richard

What do i do with things that contain more complex statements like:

if(size > 0x1ff) {
size_t sz = size;
for(ndx = 0; ndx < 32; ndx++) {
if(sz <= 0) {
break;
}
sz >>= 1;
}
ndx -= 8;
ndx <<= 9;
}
else {
ndx = size;
}

Do i have to make it into a function?

Villy Kruse
Guest
Posts: n/a

 05-24-2005
On Tue, 24 May 2005 20:24:28 +1000,
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:

>
> Do i have to make it into a function?

An inline function wouldn't be such a bad alternative if it is available
with your compiler. Otherwise, "do { ... } while (0)" is a common
ideom for making a function like macro.

Villy

Jens.Toerring@physik.fu-berlin.de
Guest
Posts: n/a

 05-24-2005
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
> Richard Bos wrote:
>> Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
>>
>>>How do i make an if/then/else macro act as a function
>>>so that the whole thing looks like the return value?

>>
>> You don't. That's what the ?: operator is for.
>>
>>>I tried this lame attempt for starters:
>>>
>>>#define A_FROM_B(b) \
>>> ( \
>>> if(b < 10) { \
>>> a = b; \

>>
>> a? What is a? What happens if I call this macro in a function where a is
>> a struct?

> Like i said, it's a lame one

>>> } \
>>> else { \
>>> a = 2*b; \
>>> }, \
>>> a; \
>>> )

>>
>> #define A_FROM_B(b) ((b)<10? (b): 2*(b))
>>
>> Note the parens around b in the definition of the macro. They will save
>> your bacon some day when you decide to call A_FROM_B(x+10).
>>
>> Richard

> What do i do with things that contain more complex statements like:

> if(size > 0x1ff) {
> size_t sz = size;
> for(ndx = 0; ndx < 32; ndx++) {
> if(sz <= 0) {
> break;
> }
> sz >>= 1;
> }
> ndx -= 8;
> ndx <<= 9;
> }
> else {
> ndx = size;
> }

> Do i have to make it into a function?

You can make a macro out of that, e.g.

#defined STRANGE_MACRO( size, ndx ) \
do { \
if ( ( size ) > 0x1ff) { \
size_t sz = ( size ); \
for ( ndx = 0; ndx < 32; ndx++ ) { \
if ( sz <= 0 ) \
break; \
sz >>= 1; \
} \
ndx -= 8; \
ndx <<= 9; \
} \
else \
ndx = ( size ); \
} while ( 0 ) \

but I would rather recommend to make that a function. Macros can
easily break when not written and used very carefully. If you e.g.
call it as

STRANGE_MACRO( size++, ndx );

then 'size' gets incremented two or three times instead of just
once as you would expect from a function call because a macro i
a simple text replacement (you could avoid that here by introdu-
cing another variable in the block and assigning the value of
'size' to it just once instead of evaluating it several times
in the macro). And, of course, if you try to call it like this

STRANGE_MACRO( size, ndx + 1 );

you'll ge a syntax error that's probably very hard to find. So why
not make the whole thing into a function?

BTW, in that macro you use a shift operation on 'sz' but also test
it for being less or equal to 0. But you can only use shift operations
safely on unsigned integers.
Regards, Jens
--
\ Jens Thoms Toerring ___ http://www.velocityreviews.com/forums/(E-Mail Removed)-berlin.de
\__________________________ http://www.toerring.de

CBFalconer
Guest
Posts: n/a

 05-24-2005
Russell Shaw wrote:
>
> How do i make an if/then/else macro act as a function
> so that the whole thing looks like the return value?
>
> I tried this lame attempt for starters:
>
> #define A_FROM_B(b) \
> ( \
> if(b < 10) { \
> a = b; \
> } \
> else { \
> a = 2*b; \
> }, \
> a; \
> )

try:

#define A_FROM_B(b) do {\
if (b < 10) a = b; \
else { \
a = 2*b; \
} \
} while (0)

The general form is "do { <stuff> } while (0)", and you are free to
write legal code for <stuff>. It does not return a usable value.

--
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)

Richard Bos
Guest
Posts: n/a

 05-24-2005
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:

> Richard Bos wrote:
> > #define A_FROM_B(b) ((b)<10? (b): 2*(b))
> >
> > Note the parens around b in the definition of the macro. They will save
> > your bacon some day when you decide to call A_FROM_B(x+10).

>
> What do i do with things that contain more complex statements like:
>
> if(size > 0x1ff) {
> size_t sz = size;
> for(ndx = 0; ndx < 32; ndx++) {
> if(sz <= 0) {
> break;
> }
> sz >>= 1;
> }
> ndx -= 8;
> ndx <<= 9;
> }
> else {
> ndx = size;
> }
>
> Do i have to make it into a function?

Have to is strong, but in practice that would be the best solution.
Modern compilers are quite good at optimising, so a function this size
would probably be inlined automatically wherever that is more efficient.

Richard

Richard Bos
Guest
Posts: n/a

 05-24-2005
Villy Kruse <(E-Mail Removed)> wrote:

> On Tue, 24 May 2005 20:24:28 +1000,
> Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
>
> > Do i have to make it into a function?

>
> An inline function wouldn't be such a bad alternative if it is available
> with your compiler. Otherwise, "do { ... } while (0)" is a common
> ideom for making a function like macro.

True, but it has one drawback: you can't return a value from one, so it
acts as a statement block, not as a function call.

Richard

SM Ryan
Guest
Posts: n/a

 05-24-2005
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> wrote:
# Hi,
#
# How do i make an if/then/else macro act as a function
# so that the whole thing looks like the return value?

You can turn the following statements into expressions. If you mind the precedence,
you can reduce the number of parentheses.

a; b (a,b)
{a} (a)
if (a) b; else c ((a)?(b)c))
expression; (expression)

With declarations and other statements, you're screwed.

Note that "a = b" is an expression. The statement "a = b;" can be converted to
"a = b".

# #define A_FROM_B(b) \
# ( \
# if(b < 10) { \
# a = b; \
# } \
# else { \
# a = 2*b; \
# }, \
# a; \
# )

( \
(b < 10) ? ( \
a = b \
) \
: ( \
a = 2*b \
), \
a \
)

--
SM Ryan http://www.rawbw.com/~wyrmwif/
Elvis was an artist. But that didn't stop him from joining the service
in time of war. That's why he is the king, and you're a shmuck.

Tim Rentsch
Guest
Posts: n/a

 05-24-2005
Russell Shaw <rjshawN_o@s_pam.netspace.net.au> writes:

> How do i make an if/then/else macro act as a function
> so that the whole thing looks like the return value?
>
> I tried this lame attempt for starters:
>
> #define A_FROM_B(b) \
> ( \
> if(b < 10) { \
> a = b; \
> } \
> else { \
> a = 2*b; \
> }, \
> a; \
> )

Many macros written in statement form can be written fairly easily in
expression form instead. Is there any reason

#define A_FROM_B(b) (a = (b)<10 ? (b) : 2*(b))

doesn't meet your needs in this case?

As a matter of good form I'd usually prefer that the assigned-to

#define ASSIGN_BAROQUELY(a,b) ((a) = (b)<10 ? (b) : 2*(b))

but that is a separate discussion.

Those macro definitions that can't be written in expression form and
that need to return a value are probably better written as functions,
whether inline functions are available or not.