By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,301 Members | 1,426 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,301 IT Pros & Developers. It's quick & easy.

Is it better to use a macro or a function?

P: n/a
Is it better to use a macro or a function?

Jun 6 '07 #1
Share this Question
Share on Google+
45 Replies


P: n/a
madhawi <ma*******@gmail.comwrites:
Is it better to use a macro or a function?
Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.
--
Ben Pfaff
http://benpfaff.org
Jun 6 '07 #2

P: n/a
madhawi wrote:
Is it better to use a macro or a function?
There are a number of things that can go wrong with function-like macros,
see C FAQ Question 10.1

so use a function, whenever you can.

--
Tor <torust [at] online [dot] no>

Jun 6 '07 #3

P: n/a
madhawi wrote:
Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

However if the functions are long, using macros can be debugging nightmare.

Tejas Kokje
Jun 6 '07 #4

P: n/a
madhawi wrote:
>
Is it better to use a macro or a function?
Yes.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h|
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>

Jun 6 '07 #5

P: n/a
Tejas Kokje wrote:
madhawi wrote:
>Is it better to use a macro or a function?

If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).
If the functions are relatively short, calling them may well not
involve any stack frame allocation /at all/. The overhead may be
roughly two instructions -- call & return. Or, of course, the compiler
may inline the function completely.

Conclusion: if you want function-like semantics, use functions.

If you want to optimise for speed, for heaven's sake /measure
first/. (Actually, if you want to optimise for anything, measure
first.)

--
Measured But Unoptimised Hedgehog
"Based on their behaviour so far -- I have no idea" /Sahara/

Jun 6 '07 #6

P: n/a
madhawi wrote:
Is it better to use a macro or a function?
Is it better to use a spoon or a saw?

--
Eric Sosman
es*****@acm-dot-org.invalid
Jun 6 '07 #7

P: n/a
In article <11*********************@i13g2000prf.googlegroups. com>,
madhawi <ma*******@gmail.comwrote:
>Is it better to use a macro or a function?
As others have said, functions are cleaner where they work. Now that
support for inline functions is widespread, another large category of
cases can be done with functions.

-- Richard

--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Jun 6 '07 #8

P: n/a
In article <ke******************************@comcast.com>,
Eric Sosman <es*****@acm-dot-org.invalidwrote:
>Is it better to use a macro or a function?
Is it better to use a spoon or a saw?
Where both are equally effective, obviously it is better to use a spoon.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Jun 6 '07 #9

P: n/a
Tejas Kokje wrote, On 06/06/07 20:28:
madhawi wrote:
>Is it better to use a macro or a function?

If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).
Apart from when it does not. I'm sure it's over 10 years since I read a
compiler manual which talked about it inlining small functions.

1st rule of optimisation, don't do it. Whilst you think using a macro is
for a small function is better due to efficiency you are not ready for
the 2nd rule.
However if the functions are long, using macros can be debugging nightmare.
The same applies to small functions.
--
Flash Gordon
Jun 6 '07 #10

P: n/a
Richard Tobin wrote:
In article <ke******************************@comcast.com>,
Eric Sosman <es*****@acm-dot-org.invalidwrote:
>>Is it better to use a macro or a function?
> Is it better to use a spoon or a saw?

Where both are equally effective, obviously it is better to use a spoon.
"There is no spoon".

--
It's Not A Trilogy, There Can Be Only One Hedgehog
A rock is not a fact. A rock is a rock.

Jun 6 '07 #11

P: n/a
Chris Dollin wrote:
Tejas Kokje wrote:
>madhawi wrote:
>>Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

If the functions are relatively short, calling them may well not
involve any stack frame allocation /at all/. The overhead may be
roughly two instructions -- call & return. Or, of course, the compiler
may inline the function completely.
I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call & return" ?

Compiler *may* inline the function. But it is not obligated to do so.

Tejas Kokje
Jun 6 '07 #12

P: n/a
Flash Gordon wrote:
Tejas Kokje wrote, On 06/06/07 20:28:
>madhawi wrote:
>>Is it better to use a macro or a function?

If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

Apart from when it does not. I'm sure it's over 10 years since I read a
compiler manual which talked about it inlining small functions.
Are there any set of rules (even for a specific compiler) which says
that small functions with x,y,z properties will always be inlined ? It
would be interesting to know those

>
1st rule of optimisation, don't do it. Whilst you think using a macro is
for a small function is better due to efficiency you are not ready for
the 2nd rule.
>However if the functions are long, using macros can be debugging
nightmare.

The same applies to small functions.
With functions you have symbols in symbol table and you can use symbolic
debugger to debug problems.

However, with long macro functions, you don't have symbols in symbol table.

Hence for long functions, I would "prefer the compiler to the
preprocessor" [Scot Myers, Effective C++].

Tejas Kokje
Jun 6 '07 #13

P: n/a
Tejas Kokje wrote:
Chris Dollin wrote:
>Tejas Kokje wrote:
>>madhawi wrote:
Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

If the functions are relatively short, calling them may well not
involve any stack frame allocation /at all/. The overhead may be
roughly two instructions -- call & return. Or, of course, the compiler
may inline the function completely.

I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call & return" ?
In the specific case I am thinking of, in the return address register,
R14, which is where the call instruction puts it.
Compiler *may* inline the function. But it is not obligated to do so.
Of course. But the compiler is not obliged to generate efficient
code for /anything/. What makes compilers generate efficient code
is selection pressure from the users of those compilers; and that
selection pressure includes "inline calls when it makes sense to
do so".

When one wants function-like things, the natural things to use are
functions. Macros (as you know, Bob) have a pleasant selection of
gotchas to choose from, so are, IMAO, best avoided as function
substitutes /unless/ you have actual good reasons otherwise -- like
a real performance problem that they fix.

--
Other Reasons Exist Hedgehog
"I just wonder when we're going to have to sit down and re-evaluate
our decision-making paradigm." /Sahara/

Jun 6 '07 #14

P: n/a
Tejas Kokje wrote:
Flash Gordon wrote:
>Tejas Kokje wrote, On 06/06/07 20:28:
>>madhawi wrote:
Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

Apart from when it does not. I'm sure it's over 10 years since I read
a compiler manual which talked about it inlining small functions.

Are there any set of rules (even for a specific compiler) which says
that small functions with x,y,z properties will always be inlined ? It
would be interesting to know those
The rules used to select functions for inline are documented with your
compiler. Most compilers I have used have options to tweak those rules
so you can balance performance and code size.

As a general rule (based on the compilers I have used), if a function
fits your criteria for a function like macro, it will fit the compiler's
criteria for an inline function.

--
Ian Collins.
Jun 6 '07 #15

P: n/a
Chris Dollin wrote:
Tejas Kokje wrote:
>Chris Dollin wrote:
>>Tejas Kokje wrote:

madhawi wrote:
Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).
If the functions are relatively short, calling them may well not
involve any stack frame allocation /at all/. The overhead may be
roughly two instructions -- call & return. Or, of course, the compiler
may inline the function completely.
I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call & return" ?

In the specific case I am thinking of, in the return address register,
R14, which is where the call instruction puts it.
I may be going off topic, but which architecture has R14 register ? Is
it a general purpose register ? I don't think it is IA32.

Tejas Kokje

>
>Compiler *may* inline the function. But it is not obligated to do so.

Of course. But the compiler is not obliged to generate efficient
code for /anything/. What makes compilers generate efficient code
is selection pressure from the users of those compilers; and that
selection pressure includes "inline calls when it makes sense to
do so".

When one wants function-like things, the natural things to use are
functions. Macros (as you know, Bob) have a pleasant selection of
gotchas to choose from, so are, IMAO, best avoided as function
substitutes /unless/ you have actual good reasons otherwise -- like
a real performance problem that they fix.
Jun 6 '07 #16

P: n/a
On Wed, 06 Jun 2007 14:42:40 -0700, in comp.lang.c , Tejas Kokje
<bi*************@gmail.comwrote:
>I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call & return" ?
Registers.
This is a very common optimisation.
>Compiler *may* inline the function. But it is not obligated to do so.
Sure, but you agree that an inline function would not have a
stackframe.
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jun 6 '07 #17

P: n/a
On Wed, 06 Jun 2007 15:29:41 -0700, in comp.lang.c , Tejas Kokje
<bi*************@gmail.comwrote:
>I may be going off topic, but which architecture has R14 register ?
www.google.com will tell you in about 0.11 seconds.
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jun 6 '07 #18

P: n/a
Mark McIntyre wrote:
On Wed, 06 Jun 2007 14:42:40 -0700, in comp.lang.c , Tejas Kokje
<bi*************@gmail.comwrote:
>I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call & return" ?

Registers.
This is a very common optimisation.
Which ones for x86 architecture ? Also what if you want to pass
arguments ? Will they be stored in registers as well ?
>Compiler *may* inline the function. But it is not obligated to do so.

Sure, but you agree that an inline function would not have a
stackframe.
I don't know how inline functions are implemented by compilers. But I
would be surprised if compiler inlined a function without me telling it
to do so (-O, -O2 etc for gcc).

Tejas Kokje
Jun 6 '07 #19

P: n/a
Tejas Kokje wrote, On 06/06/07 22:42:
Chris Dollin wrote:
>Tejas Kokje wrote:
>>madhawi wrote:
Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

If the functions are relatively short, calling them may well not
involve any stack frame allocation /at all/. The overhead may be
roughly two instructions -- call & return. Or, of course, the compiler
may inline the function completely.

I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call & return" ?
In the register or other space specifically designed for storing it.
Compiler *may* inline the function. But it is not obligated to do so.
Inlining the code can lead to a slower program because sometimes
increasing the size of the executable means more cache misses. The
optimiser is far more likely to judge this correctly than you especially
as you seem to be assuming inlining will always speed things up.
--
Flash Gordon
Jun 6 '07 #20

P: n/a
Tejas Kokje wrote, On 06/06/07 22:50:
Flash Gordon wrote:
>Tejas Kokje wrote, On 06/06/07 20:28:
>>madhawi wrote:
Is it better to use a macro or a function?
If functions are relatively short, using a macro is better since it
avoids overhead of stack frame allocation ( saving stack pointer of
caller,saving return address of the instruction in caller function on
the stack frame etc).

Apart from when it does not. I'm sure it's over 10 years since I read
a compiler manual which talked about it inlining small functions.

Are there any set of rules (even for a specific compiler) which says
that small functions with x,y,z properties will always be inlined ? It
would be interesting to know those
Yes, in the manual I read over 10 years ago! If you want a more recent
example, read the documentation for gcc.
>1st rule of optimisation, don't do it. Whilst you think using a macro
is for a small function is better due to efficiency you are not ready
for the 2nd rule.
>>However if the functions are long, using macros can be debugging
nightmare.

The same applies to small functions.

With functions you have symbols in symbol table and you can use symbolic
debugger to debug problems.

However, with long macro functions, you don't have symbols in symbol table.

Hence for long functions, I would "prefer the compiler to the
preprocessor" [Scot Myers, Effective C++].
I was not sufficiently clear. I meant replacing small functions with
macros can also make debugging a nightmare and therefore it should not
be done unless there is a specific reason in that particular case (e.g.
you have measured, found you have a problem, and found that changing to
using a macro will actually speed things up significantly).
--
Flash Gordon
Jun 6 '07 #21

P: n/a
Chris Dollin <eh@electrichedgehog.netwrites:
Richard Tobin wrote:
>In article <ke******************************@comcast.com>,
Eric Sosman <es*****@acm-dot-org.invalidwrote:
>>>Is it better to use a macro or a function?
>> Is it better to use a spoon or a saw?

Where both are equally effective, obviously it is better to use a spoon.

"There is no spoon".
But I saw a spoon!

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jun 7 '07 #22

P: n/a
Ben Pfaff wrote:
madhawi <ma*******@gmail.comwrites:
>Is it better to use a macro or a function?

Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.
Ok, I'll bite. Why is a function safer than a function-like macro?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jun 7 '07 #23

P: n/a
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Joe Wright wrote:
Ben Pfaff wrote:
>madhawi <ma*******@gmail.comwrites:
>>Is it better to use a macro or a function?

Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.

Ok, I'll bite. Why is a function safer than a function-like macro?
One reason (not necessarily the reason Ben was thinking of) is that
side-effects can be contained when you use a function.

Think of what
foo(getchar())
might do, if foo() were
#define foo(x) (x+x)
versus
int foo(int x) { return x+x; }

- --
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
- ---------- Slackware - Because I know what I'm doing. ------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Armoured with GnuPG

iD8DBQFGZ2MIagVFX4UWr64RArcFAKDWk/uzLIRvMKniYVa0Rkk1VQaflwCdG+ML
Rbrs0LpddqmfFLY7ikPCSv4=
=pBKk
-----END PGP SIGNATURE-----
Jun 7 '07 #24

P: n/a
Lew Pitcher <lp******@teksavvy.comwrites:
Joe Wright wrote:
>Ben Pfaff wrote:
>>madhawi <ma*******@gmail.comwrites:

Is it better to use a macro or a function?

Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.

Ok, I'll bite. Why is a function safer than a function-like macro?

One reason (not necessarily the reason Ben was thinking of) is that
side-effects can be contained when you use a function.
Also, functions provide a higher degree of type-safety.
--
"I've been on the wagon now for more than a decade. Not a single goto
in all that time. I just don't need them any more. I don't even use
break or continue now, except on social occasions of course. And I
don't get carried away." --Richard Heathfield
Jun 7 '07 #25

P: n/a
On Jun 7, 5:55 am, Keith Thompson <k...@mib.orgwrote:
Chris Dollin <e...@electrichedgehog.netwrites:
Richard Tobin wrote:
In article <keWdnUK-UI-wg_rbnZ2dnUVZ_gmdn...@comcast.com>,
Eric Sosman <esos...@acm-dot-org.invalidwrote:
>>Is it better to use a macro or a function?
> Is it better to use a spoon or a saw?
Where both are equally effective, obviously it is better to use a spoon.
"There is no spoon".

But I saw a spoon!
Care to choose the blue/red pill? :-)
>
--
Keith Thompson (The_Other_Keith) k...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Jun 7 '07 #26

P: n/a
Tejas Kokje wrote:
Chris Dollin wrote:
>In the specific case I am thinking of, in the return address register,
R14, which is where the call instruction puts it.

I may be going off topic, but which architecture has R14 register ?
Several have /an/ R14, but the R14 I have in mind is that of the ARM.
Is it a general purpose register ?
Yes. Apart from having the return address stuffed into it on
a call, it's a plain ordinary register, AFAIR.

(As opposed to R15, the PC, which has some careful restrictions
on its use -- but is still a register.)
I don't think it is IA32.
Neither do I.

--
Four-ARMed Is To Be Envied Hedgehog
"No-one here is exactly what he appears." G'kar, /Babylon 5/

Jun 7 '07 #27

P: n/a
On Jun 7, 8:44 am, Lew Pitcher <lpitc...@teksavvy.comwrote:
Ben Pfaff wrote:
Some tasks can only be accomplished with a macro.
Otherwise, use a function: in general, they're safer.
One reason (not necessarily the reason Ben was thinking of) is that
side-effects can be contained when you use a function.
Historical tidbit: The way SunOS 3.5 calculated date
involved a "month++" or some such that was passed to a macro.
IIRC it failed March 1, 1989 after working fine for
over a year! (Programmers: please test date-dependent
routines for more than just today's date!)

I was working at a Sun lab late on Feb. 28 1989 and
noticed worried messages appearing on Usenet from
Sun machines in Australia. (IIRC the messages were
posted to sun.whatever, not comp.sun.whatever, so
probably aren't in archive.)

I agree with the comment downthread that spoons are
preferable to saws when both do the job. But there
are instances where (sometimes very) complicated macros
*are* just the right solution to a programming problem.

For some reason the *correct* reason to use macros
reminds me of these quotations:
The present letter is a very long one, simply because
I had no leisure to make it shorter.
- Blaise Pascal (1623-62)
I didn't have time to write a short letter, so I wrote
a long one instead.
- Mark Twain (1835-1910)
jamesdowallen at gmail

Jun 7 '07 #28

P: n/a
Tejas Kokje wrote, On 06/06/07 23:52:
Mark McIntyre wrote:
>On Wed, 06 Jun 2007 14:42:40 -0700, in comp.lang.c , Tejas Kokje
<bi*************@gmail.comwrote:
>>I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do "call &
return" ?

Registers. This is a very common optimisation.

Which ones for x86 architecture ? Also what if you want to pass
arguments ? Will they be stored in registers as well ?
Try reading the documentation for a few compilers. You will often find
it tells you what optimisations are done.
>>Compiler *may* inline the function. But it is not obligated to do so.

Sure, but you agree that an inline function would not have a
stackframe.

I don't know how inline functions are implemented by compilers. But I
would be surprised if compiler inlined a function without me telling it
to do so (-O, -O2 etc for gcc).
Be surprised then. Also try reading the documentation instead of assuming.
--
Flash Gordon
Jun 7 '07 #29

P: n/a
Keith Thompson wrote:
Chris Dollin <eh@electrichedgehog.netwrites:
>Richard Tobin wrote:
>>In article <ke******************************@comcast.com>,
Eric Sosman <es*****@acm-dot-org.invalidwrote:

Is it better to use a macro or a function?
Is it better to use a spoon or a saw?
Where both are equally effective, obviously it is better to use a spoon.
"There is no spoon".

But I saw a spoon!
Morpheus: Your mind makes it real

--
Tor <torust [at] online [dot] no>
Jun 7 '07 #30

P: n/a
Ben Pfaff wrote:
madhawi <ma*******@gmail.comwrites:
>Is it better to use a macro or a function?

Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.
An example:
I have in some of my programs a lot of pointers to structs.

struct a
{
char *s1;
char *s2
} *b;

char *s;

A general problem then is that such a pointer might be NULL and
therefore referencing a member of that struct is illegal.

s=b->s1; /*if b is NULL this doesn't work well...*/

Now if what I want is something like this:
if (b)
s=b->s1;
else
s=NULL;

That is I want to assign *something* to s, if b is NULL (or for that
matter b->s1 is NULL) I do want s to be NULL too. This could be written:
s=b?b->s1:NULL;

That's OK, so know if b isn't really a variable but rather a long
complex expression I need to type that twice to get the desired effect.

#define spt(ptr)(!(ptr))?NULL:ptr

would make it possible to write
s=spt(b)->s1;

That trick is *not* possible with a function!
Oh, and before someone points it out, it is not entirely safe either, an
expression in the place of b with side effects would not do what is
intended! But it have helped me write some shorter and more (IMO)
readable code. The expression b is evaluated twice if it is non-NULL,
but as long as it doesn't have side effects and there is no speed
requirements or the compiler is good enough at optimizing that doesn't
matter.

It is even possible to chain them like this (obviously with some other
declarations necessary)
res=spt(spt(spt(ptr)->member)->member)->member;

This allows for every step to be NULL and expands to (line breaks
inserted for readability):
res=(!((!((!(ptr))?NULL:ptr->member))?NULL:(!(ptr))?NULL:
ptr->member->member))?NULL:(!((!(ptr))?NULL:ptr->member))?NULL:
(!(ptr))?NULL:ptr->member->member->member;

and doing exactly what I want but much more readable with the macro
than without. Of course typing
if (ptr)
{
if (ptr->member)
{
if (ptr->member->member)
res=ptr->member->member->member;
else
res=NULL;
}
else
res=NULL;
}
else
res=NULL;

would also produce the same result but would not (again IMO) be as readable.

Oh, once again, don't try this at home unless you understand the
restriction "expression *must* be without side effects"
Jun 7 '07 #31

P: n/a
In article <4K*********************@telenor.com>,
Tor Rustad <to********@hotmail.comwrote:
>>>Where both are equally effective, obviously it is better to use a spoon.
>>"There is no spoon".
>But I saw a spoon!
>Morpheus: Your mind makes it real
Sometimes I suspect that I am completely out of touch with popular
culture.

-- Richard

--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Jun 7 '07 #32

P: n/a
Johan Bengtsson <qw*******@hotmail.comwrites:
Ben Pfaff wrote:
>madhawi <ma*******@gmail.comwrites:
>>Is it better to use a macro or a function?

Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.

An example:
I have in some of my programs a lot of pointers to structs.

struct a
{
char *s1;
char *s2
} *b;

char *s;

A general problem then is that such a pointer might be NULL and
therefore referencing a member of that struct is illegal.

s=b->s1; /*if b is NULL this doesn't work well...*/

Now if what I want is something like this:
if (b)
s=b->s1;
else
s=NULL;

That is I want to assign *something* to s, if b is NULL (or for that
matter b->s1 is NULL) I do want s to be NULL too. This could be
written:
s=b?b->s1:NULL;

That's OK, so know if b isn't really a variable but rather a long
complex expression I need to type that twice to get the desired
effect.

#define spt(ptr)(!(ptr))?NULL:ptr

would make it possible to write
s=spt(b)->s1;

That trick is *not* possible with a function!
Did you consider:

struct a *spt(struct a *b)
{
static struct a null_a = { NULL, NULL };
return b ? b : &null_a;
}
Sure, you need one for each structure type, that is one thing macros
are *really* good for. You get more type safety, and when the time
comes (as it always does on my programs) you have somewhere to put
your printfs!

--
Ben.
Jun 8 '07 #33

P: n/a
Johan Bengtsson wrote:
>
#define spt(ptr)(!(ptr))?NULL:ptr
This makes spt(ptr) equivalent to ptr.
would make it possible to write
s=spt(b)->s1;
No, it wouldn't.

Tim S
Jun 8 '07 #34

P: n/a
On 2007-06-08 10:00:28 -0700, Numeromancer <ts*****@sbcglobal.netsaid:
Johan Bengtsson wrote:
>>
#define spt(ptr)(!(ptr))?NULL:ptr

This makes spt(ptr) equivalent to ptr.
Not exactly
>
>would make it possible to write
s=spt(b)->s1;

No, it wouldn't.

Yes it does. After preprocessing:

s = spt(b)->s1;

becomes:

s = (!(b))?NULL:b->s1;

which, assuming that the evaluation of b has no side effects, is
functionally equivalent to :
if(b)
s = b->s1;
else
s = NULL;
--
Clark S. Cox III
cl*******@gmail.com

Jun 8 '07 #35

P: n/a
Ben Bacarisse wrote:
Johan Bengtsson <qw*******@hotmail.comwrites:
>Ben Pfaff wrote:
>>madhawi <ma*******@gmail.comwrites:

Is it better to use a macro or a function?
Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.
An example:
I have in some of my programs a lot of pointers to structs.

struct a
{
char *s1;
char *s2
} *b;

char *s;

A general problem then is that such a pointer might be NULL and
therefore referencing a member of that struct is illegal.

s=b->s1; /*if b is NULL this doesn't work well...*/

Now if what I want is something like this:
if (b)
s=b->s1;
else
s=NULL;

That is I want to assign *something* to s, if b is NULL (or for that
matter b->s1 is NULL) I do want s to be NULL too. This could be
written:
s=b?b->s1:NULL;

That's OK, so know if b isn't really a variable but rather a long
complex expression I need to type that twice to get the desired
effect.

#define spt(ptr)(!(ptr))?NULL:ptr

would make it possible to write
s=spt(b)->s1;

That trick is *not* possible with a function!

Did you consider:

struct a *spt(struct a *b)
{
static struct a null_a = { NULL, NULL };
return b ? b : &null_a;
}
Sure, you need one for each structure type, that is one thing macros
are *really* good for. You get more type safety, and when the time
comes (as it always does on my programs) you have somewhere to put
your printfs!
I might be dumb, but I don't see how that solves the same thing as the
macro.

I repeat myself...

#define spt(ptr) (!(ptr))?NULL:ptr
a=spt(b)->c;
expands to
a=(!(ptr))?NULL:ptr->c;

now if ptr is not NULL: (normal case)
a=ptr->c;
and if ptr is NULL:
a=NULL;

You see? the ->c part "disappears" because of the macro even if it is
outside what looks like the call, and that is the code that might
actually crash the program.

And the part about type safety, well I would probably need hundreds (if
not thousands) of those functions in that project... (I could write it
so I have one function for each struct *and* each member of that struct,
but that would be a *lot* of functions)

And the speed would suffer too I think... I guess (but have not
verified) that the speed difference (on most systems with fairly good
optimizing compilers) with the macro (vs not having any checks at all)
would be that of the two assembler instructions needed to compare the
pointer to NULL and then make a conditional jump.
Jun 9 '07 #36

P: n/a
Johan Bengtsson <qw*******@hotmail.comwrites:
Ben Bacarisse wrote:
>Johan Bengtsson <qw*******@hotmail.comwrites:
>>Ben Pfaff wrote:
madhawi <ma*******@gmail.comwrites:

Is it better to use a macro or a function?
Some tasks can only be accomplished with a macro. Otherwise, use
a function: in general, they're safer.
An example:
I have in some of my programs a lot of pointers to structs.

struct a
{
char *s1;
char *s2
} *b;

char *s;

A general problem then is that such a pointer might be NULL and
therefore referencing a member of that struct is illegal.

s=b->s1; /*if b is NULL this doesn't work well...*/
<snip>
>>>
#define spt(ptr)(!(ptr))?NULL:ptr

would make it possible to write
s=spt(b)->s1;

That trick is *not* possible with a function!

Did you consider:

struct a *spt(struct a *b)
{
static struct a null_a = { NULL, NULL };
return b ? b : &null_a;
}
Sure, you need one for each structure type, that is one thing macros
are *really* good for. You get more type safety, and when the time
comes (as it always does on my programs) you have somewhere to put
your printfs!
I might be dumb, but I don't see how that solves the same thing as the
macro.
You are right it does something different, but unless I missed what
you were doing, the important part is dealing simply with a null pointer.
I repeat myself...

#define spt(ptr) (!(ptr))?NULL:ptr
a=spt(b)->c;
expands to
a=(!(ptr))?NULL:ptr->c;

now if ptr is not NULL: (normal case)
a=ptr->c;
and if ptr is NULL:
a=NULL;

You see? the ->c part "disappears" because of the macro even if it is
outside what looks like the call, and that is the code that might
actually crash the program.
Yes, but making the "->c" disappear did not seem to me to be the key
part of what you wanted. I was suggesting a way to make spt(b)->c
always valid (indeed the function makes spt(b) always valid).
And the part about type safety, well I would probably need hundreds
(if not thousands) of those functions in that project... (I could
write it so I have one function for each struct *and* each member of
that struct, but that would be a *lot* of functions)
I don't follow this. You do need one per struct, but why for each
member?

It is not my purpose to start a style war (that's why I just said
"have you considered..."). I tend not to worry about shaving a few
instructions off a piece of code, but I do worry about syntactically
fragile macros.

--
Ben.
Jun 9 '07 #37

P: n/a
Ben Bacarisse wrote:
Johan Bengtsson <qw*******@hotmail.comwrites:

Yes, but making the "->c" disappear did not seem to me to be the key
part of what you wanted. I was suggesting a way to make spt(b)->c
always valid (indeed the function makes spt(b) always valid).
Oh, sorry, but that was exactly the point. I do think we agree at the
end then...
>
I don't follow this. You do need one per struct, but why for each
member?
Umm, probably because you missed my main point (the handling of the last
->member part).
It is not my purpose to start a style war (that's why I just said
"have you considered..."). I tend not to worry about shaving a few
instructions off a piece of code, but I do worry about syntactically
fragile macros.
It's ok with me, I do accept your suggestion but it didn't solve the
same thing as the macro (because I somehow didn't get my point thru to you).

I think I basically do agree with you, sometimes a function (probably
preferably an inline function so the optimizer might do some additional
tricks) is the right tool for the job and sometimes a macro is.

inline double squaredouble(double a) { return a*a; }
would be preferable to
#define square(a) ((a)*(a))
Jun 9 '07 #38

P: n/a
Johan Bengtsson <qw*******@hotmail.comwrites:
Ben Bacarisse wrote:
>Johan Bengtsson <qw*******@hotmail.comwrites:

Yes, but making the "->c" disappear did not seem to me to be the key
part of what you wanted. I was suggesting a way to make spt(b)->c
always valid (indeed the function makes spt(b) always valid).
Oh, sorry, but that was exactly the point. I do think we agree at the
end then...
No, I think we are have a sound and reasonable disagreement! I did
not miss the point about the ->c part "dropping off" when the macro
is used. I was suggesting that it *might* be better to let go of that
objective.

I (and I am sure I am not alone) have an aversion to macros that
silently miss-behave when combined with C's syntax rules. In your
case, for example, sptb(b)->c is (silently) quite different to
"(spt(b))->c" and "(*spt(b)).c" and the effect of expressions like
"spt(*pp)->c" and "spt(b)->c || f(x)" are best described as
"interesting".

I have no delusions of persuading you on this point. I am sure you
will say that all intelligent programmers must beware of such
pitfalls, and only a fool would write "spt(*pp)->c" and expect it to
mean (roughly) the same as "v = *pp; spt(v)->c". You may be right,
but there is often merit in making your code "fool"-proof.

--
Ben.
Jun 11 '07 #39

P: n/a
Ben Bacarisse wrote:
Johan Bengtsson <qw*******@hotmail.comwrites:
>Ben Bacarisse wrote:
>>Johan Bengtsson <qw*******@hotmail.comwrites:

Yes, but making the "->c" disappear did not seem to me to be the key
part of what you wanted. I was suggesting a way to make spt(b)->c
always valid (indeed the function makes spt(b) always valid).
Oh, sorry, but that was exactly the point. I do think we agree at the
end then...

No, I think we are have a sound and reasonable disagreement! I did
not miss the point about the ->c part "dropping off" when the macro
is used. I was suggesting that it *might* be better to let go of that
objective.
Umm, If your function is used the program will most surely crash for
those cases where it would make any difference to have the function
compared to not have it, it is pointless but the macro isn't.
>
I (and I am sure I am not alone) have an aversion to macros that
silently miss-behave when combined with C's syntax rules. In your
case, for example, sptb(b)->c is (silently) quite different to
"(spt(b))->c" and "(*spt(b)).c" and the effect of expressions like
"spt(*pp)->c" and "spt(b)->c || f(x)" are best described as
"interesting".
Oh, I do definitely not agree with you there, that's fine however - in
this case it is a genuine disagreement and can be left as one.
>
I have no delusions of persuading you on this point. I am sure you
will say that all intelligent programmers must beware of such
pitfalls, and only a fool would write "spt(*pp)->c" and expect it to
mean (roughly) the same as "v = *pp; spt(v)->c". You may be right,
but there is often merit in making your code "fool"-proof.
Agreed, there is however also a point in making it readable and it those
two goals are in conflict - what to pick? Well that is a thing to have
as much disagreement as wanted.

a=spt(*pp)->c;

would mean exactly the same as

v=*pp;
a=spt(v)->c;

just typing
spt(*pp)->c;
would be quite pointless (excuse me for the joke) since it doesn't do
anything and have no side effects. Did you intend this: spt(*pp++)->c;
Because then I do agree that it is dangerous and your point is valid,
your solution, however, isn't.

Jun 12 '07 #40

P: n/a
Johan Bengtsson <qw*******@hotmail.comwrites:
Ben Bacarisse wrote:
>Johan Bengtsson <qw*******@hotmail.comwrites:
>>Ben Bacarisse wrote:
Johan Bengtsson <qw*******@hotmail.comwrites:

Yes, but making the "->c" disappear did not seem to me to be the key
part of what you wanted. I was suggesting a way to make spt(b)->c
always valid (indeed the function makes spt(b) always valid).
Oh, sorry, but that was exactly the point. I do think we agree at the
end then...

No, I think we are have a sound and reasonable disagreement! I did
not miss the point about the ->c part "dropping off" when the macro
is used. I was suggesting that it *might* be better to let go of that
objective.
Umm, If your function is used the program will most surely crash for
those cases where it would make any difference to have the function
compared to not have it, it is pointless but the macro isn't.
Ah, then if you are right I have misunderstood. Please give me an
example because the function I suggested did not, I think, "crash" if
used in the context you originally posted (s=spt(b)->s1;). Of course,
I often make mistakes, but I've looked again and I don't see what you
mean.
>I (and I am sure I am not alone) have an aversion to macros that
silently miss-behave when combined with C's syntax rules. In your
case, for example, sptb(b)->c is (silently) quite different to
"(spt(b))->c" and "(*spt(b)).c" and the effect of expressions like
"spt(*pp)->c" and "spt(b)->c || f(x)" are best described as
"interesting".
Oh, I do definitely not agree with you there, that's fine however - in
this case it is a genuine disagreement and can be left as one.
OK!
>I have no delusions of persuading you on this point. I am sure you
will say that all intelligent programmers must beware of such
pitfalls, and only a fool would write "spt(*pp)->c" and expect it to
mean (roughly) the same as "v = *pp; spt(v)->c". You may be right,
but there is often merit in making your code "fool"-proof.
Agreed, there is however also a point in making it readable and it
those two goals are in conflict - what to pick? Well that is a thing
to have as much disagreement as wanted.

a=spt(*pp)->c;

would mean exactly the same as

v=*pp;
a=spt(v)->c;
Yes, that is what I meant. I should have written "mean (roughly) the
same as '(v = *pp), (spt(v)->c)'. In other words I was extolling the
virtue of what is often called referential transparency in
expressions. You've said above that you don't value it, so I will not
push the case any more.
Did you intend this: spt(*pp++)->c;
Because then I do agree that it is dangerous and your point is valid,
your solution, however, isn't.
That is not what I meant, but I *could* have written it because it
gives a good example of why a function is so often a safer solution.
spt(*pp++)->c is dangerous when spt is the macro you posted but is
safer (in that it has fewer surprises in what it means) if it is the
function I gave. All this, of course, subject to your first point -- I
can't see the error to which you refer.

[BTW, this thread having gone on longer than I'd expected, I've had
time to reflect that I should have made spt return a "const struct A
*" -- such functions are safer still if they object they return a pointer
to is read-only.]

--
Ben.
Jun 12 '07 #41

P: n/a
"Tejas Kokje" <bi*************@gmail.comwrote in message
news:11***************@sj-nntpcache-2.cisco.com...

<OT>
Mark McIntyre wrote:
>On Wed, 06 Jun 2007 14:42:40 -0700, in comp.lang.c , Tejas Kokje
<bi*************@gmail.comwrote:
>>I didn't get your first comment. If you don't allocate stack frame,
where are you going to store return address when you do
"call & return" ?

Registers. This is a very common optimisation.

Which ones for x86 architecture ?
x86 doesn't store the return address in a register, but it's possible for
simple leaf functions to not have their own stack frames, just require
callers to push the return address on the stack. Also, the latest AMD and
Intel chips can optimize stack instructions and simple calls so that they're
(nearly?) free.

OTOH, most of the RISCs I'm aware of have a "link" register that holds the
most recent return address. Only non-leaf functions have to push that onto
the stack or save it in another register.
Also what if you want to pass arguments ? Will they be stored in
registers as well ?
Many calling conventions do that; it's not x86's default for any ABI I'm
aware of, though it's usually selectable, and it's the default on many other
architectures (including AMD64).
>>Compiler *may* inline the function. But it is not obligated to do so.

Sure, but you agree that an inline function would not have a
stackframe.

I don't know how inline functions are implemented by compilers. But I
would be surprised if compiler inlined a function without me telling it to
do so (-O, -O2 etc for gcc).
Any decent compiler set to high optimization levels will inline a function
if it makes sense and the source is available, particularly if you mark it
"inline". They also usually have a variety of knobs you can play with to
fine-tune their choices, but the defaults are tuned so that they'll be
near-optimal in almost all cases. You're more likely to make things worse
than better when you second-guess a modern compiler.

</OT>

Returning to the original question, function-like macros have many gotchas
that trip up novices. They were frequently used to improve performance over
functions back in the days compilers weren't so good, but today the
difference (if any) should be minimal and usually doesn't justify the risk.
Lots of people, however, still use them out of inertia or ignorance, so
don't be surprised when you see them.

Personally, I only use function-like macros when I want to take advantage of
those gotchas, e.g. when I need a function _not_ to be type-safe or to be
able to modify its arguments. If a "static inline" function meets my needs,
that's what I'll use.

S

--
Stephen Sprunk "Those people who think they know everything
CCIE #3723 are a great annoyance to those of us who do."
K5SSS --Isaac Asimov
--
Posted via a free Usenet account from http://www.teranews.com

Jun 12 '07 #42

P: n/a
Hello,

Stephen Sprunk wrote:
x86 doesn't store the return address in a register, but it's possible for
simple leaf functions to not have their own stack frames, just require
callers to push the return address on the stack.
<ot>

Which can be dangerous in some cases. At one point, I was debugging
some code a co-worker had written.

So, the collegue did not generate stack-frame. Now, the machine the code
was running own showed erroneous behaviour, or even crashed. What did
happen? Out of a habbit, he had left out the stack frame, as he was
writing a leaf function. In this case, it was hand-written assembly, but
the problem could have been produced by a compiler if it left out a
stack-frame, too.

The problem here was that this was kernel-mode code, that is, code in
ring 0. The code shared the stack with every other part of the operating
system. Thus, whenever an interrupt occurred, the local variables were
overwritten be the interrupt routine. I think you get the picture.

so, what is the bottom line of this story: Saving some clock ticks by
leaving out the stack frame might seem to be a good idea, but one should
not forget that there are circumstances where this is not a good idea.
IMHO, a compiler should NEVER perform such risky tasks without
specifically being asked to do so.

</ot>
Any decent compiler set to high optimization levels will inline a function
if it makes sense and the source is available, particularly if you mark it
"inline". They also usually have a variety of knobs you can play with to
fine-tune their choices, but the defaults are tuned so that they'll be
near-optimal in almost all cases. You're more likely to make things worse
than better when you second-guess a modern compiler.
In many cases, you might be right. Sometimes, one is really surprised
how the compiler optimized some code you would never have thought about.

Unfortunately, in many other cases, many "obvious" optimizations are not
done at all.

to summarize, a doubt the choices are near-optimal
_in_almost_all_cases_. They might be very good in many cases, but that
is all.

Of course, it depends if it is worth to play with the knobs in a
particular case. Often, you can live with the default solution without
problems.

Regards,
Spiro.

--
Spiro R. Trikaliotis http://opencbm.sf.net/
http://www.trikaliotis.net/ http://www.viceteam.org/
Jun 13 '07 #43

P: n/a
Spiro Trikaliotis wrote:
Hello,

Stephen Sprunk wrote:
>x86 doesn't store the return address in a register, but it's possible for
simple leaf functions to not have their own stack frames, just require
callers to push the return address on the stack.

<ot>

Which can be dangerous in some cases. At one point, I was debugging
some code a co-worker had written.

So, the collegue did not generate stack-frame. Now, the machine the code
was running own showed erroneous behaviour, or even crashed. What did
happen? Out of a habbit, he had left out the stack frame, as he was
writing a leaf function. In this case, it was hand-written assembly, but
the problem could have been produced by a compiler if it left out a
stack-frame, too.
Then it would be called a "bug", and fixed when spotted. Compilers have
lots of places where they can have bugs: leaf optimisation isn't
special here.
so, what is the bottom line of this story: Saving some clock ticks by
leaving out the stack frame might seem to be a good idea, but one should
not forget that there are circumstances where this is not a good idea.
Indeed.
IMHO, a compiler should NEVER perform such risky tasks without
specifically being asked to do so.
It's not "risky" if it's done properly. I think the compiler should
do leaf optimisation /routinely/ -- this gives the best chance for problems
to be detected early.

--
Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Jun 14 '07 #44

P: n/a
Ben Bacarisse wrote:
Johan Bengtsson <qw*******@hotmail.comwrites:
>Ben Bacarisse wrote:
>>Johan Bengtsson <qw*******@hotmail.comwrites:

Ben Bacarisse wrote:
Johan Bengtsson <qw*******@hotmail.comwrites:
>
Yes, but making the "->c" disappear did not seem to me to be the key
part of what you wanted. I was suggesting a way to make spt(b)->c
always valid (indeed the function makes spt(b) always valid).
Oh, sorry, but that was exactly the point. I do think we agree at the
end then...
No, I think we are have a sound and reasonable disagreement! I did
not miss the point about the ->c part "dropping off" when the macro
is used. I was suggesting that it *might* be better to let go of that
objective.
Umm, If your function is used the program will most surely crash for
those cases where it would make any difference to have the function
compared to not have it, it is pointless but the macro isn't.

Ah, then if you are right I have misunderstood. Please give me an
example because the function I suggested did not, I think, "crash" if
used in the context you originally posted (s=spt(b)->s1;). Of course,
I often make mistakes, but I've looked again and I don't see what you
mean.
Ahh, sorry, now I see how it works - thanks. You are right that it
should work like that too, I do however like my macro better partly
because it isn't type safe (and can be applied to all types of pointers
to structs without the need to create one for each type). But to answer
your original reply: no I didn't consider that.

<OT>
The fact that I like my macro better than the function is however a
proper disagreement and is partly because I have a quite large number of
structs in the project where this code is found. Besides that it is a
WIN32 program with a large number of dll:s and that would require me to
either export each of those functions from the dll where the struct is
"defined", or create one instance of each such function in each dll.
Yes I know that "define" and structs doesn't really mix well, they are
declared in headers specific to a certain dll and then used in other dll:s.
</OT>
>
That is not what I meant, but I *could* have written it because it
gives a good example of why a function is so often a safer solution.
spt(*pp++)->c is dangerous when spt is the macro you posted but is
safer (in that it has fewer surprises in what it means) if it is the
function I gave. All this, of course, subject to your first point -- I
can't see the error to which you refer.
I see that, because the error was mine, thanks!
Jun 15 '07 #45

P: n/a
Hello Chris,

In my opinion, your are contradicting yourself:

Chris Dollin <ch**********@hp.comschrieb:
Spiro Trikaliotis wrote:
>Out of a habbit, he had left out the stack frame, as he was
writing a leaf function. In this case, it was hand-written assembly, but
the problem could have been produced by a compiler if it left out a
stack-frame, too.

Then it would be called a "bug", and fixed when spotted. Compilers have
lots of places where they can have bugs: leaf optimisation isn't
special here.
Here, you call that type of optimisation a "bug", while:
>IMHO, a compiler should NEVER perform such risky tasks without
specifically being asked to do so.

It's not "risky" if it's done properly. I think the compiler should
do leaf optimisation /routinely/ -- this gives the best chance for problems
to be detected early.
Here, you tell me that it is not risky if it's done properly.

This optimisation is something done very frequently, But, depending on
the circumstances, it can work perfectly (because a "leaf function" is
really a leaf function, as the environment guarantees that no other
function can interfere with the stack), while in other circumstances
(kernel-mode on Windows or Linux, and, most probably, in many other
cases), the leaf function cannot be guaranteed that it is a leaf
function, as an interrupt outside of the scope of the compiled piece of
code can interfere, using the same stack.

Regards,
Spiro.

--
Spiro R. Trikaliotis http://opencbm.sf.net/
http://www.trikaliotis.net/ http://www.viceteam.org/
Jun 16 '07 #46

This discussion thread is closed

Replies have been disabled for this discussion.