inline vs macro

R

Richard Heathfield

(e-mail address removed) said:
No. I am saying that you do not know if MAX(a,b) is a macro or a
function unless you examine the implementation.

Or read the docs. And if it's a function, you don't know what it does unless
you examine the implementation, or read the docs. So you have to do this
anyway.
MAX(++a,++b) is prefectly fine if it is a function and we do not know
if it is OK if it is a macro.

Sure. So read the docs for MAX.
The arguments are stupid if it is a macro and not stupid if it is a
function. But you cannot tell which is which unless you see the actual
definition. In a ten million line C project, will you know for sure
which things are macros and which things are functions?

Read the documentation. Knowing what it is that you're calling - or being
able to find out - is part of being a programmer.
By their very nature, function macros are defective and cause defects.

No, by their very nature, programmers are defective and cause defects. They
can cause these defects just as devastatingly in functions as they can in
macros. Indeed, more so, since there are more places to hide a function's
source code (the macro's source has to be visible, to a certain extent, or
the preprocessor won't be able to find it - the same cannot be said of a
function).
Reusing bad software is worse than not reusing it.

Right. And writing bad macros (or calling good macros in a bad way) is worse
than not writing them. That doesn't mean we can't write good macros, and
call them in a good way.
Wrong. It is used safely when you never input more bytes than the size
of the object.

Quibbling over use of the word "use". What I mean is that a programmer who
puts a call to gets() into a program is risk-exposing his program and
potentially any computer system on which it is used.
In a similar way, function macros are fatally flawed. They can be used
safely, but normal use is not safe.


Just like gets() -- only with extreme care.

No, gets() has no safe use (see above).
 
R

Richard Heathfield

jaysome said:

But, what I suspect that Dann meant, was: "Lack of *undesired* side
effects due to multiple evaluation"; something like this:

#define ABS(x) ((x) < 0 ? -(x) : (x))
... ABS( n++ )

Fine, so don't call it that way.
Barring any undefined behavior, use of void * seems type safe to me.

In other words, if you use it right, void * is fine, and if you don't, it
isn't. Well, gosh. :)

But surely the whole point of type safety is that the compiler should yell
when you do something type-unsafe, yes?

But the compiler will not yell at this (fragment):

char c = 'A';
char *p = c;
void *q = p;
int *r = q;
*r = INT_MAX;

void * discards type safety.
 
I

Ian Collins

Richard said:
jaysome said:



Fine, so don't call it that way.


In other words, if you use it right, void * is fine, and if you don't, it
isn't. Well, gosh. :)

But surely the whole point of type safety is that the compiler should yell
when you do something type-unsafe, yes?

But the compiler will not yell at this (fragment):
Another good reason for compiling C with a C++ compiler :)
char c = 'A';
char *p = c;

Surely it is obliged to issue a diagnostic here?
 
R

Richard Heathfield

Ian Collins said:

Surely it is obliged to issue a diagnostic here?

Er, make that &c :)

I originally had c as an array, and changed my mind. Obviously not
thoroughly enough.
 
J

jaysome

jaysome said:



Fine, so don't call it that way.


In other words, if you use it right, void * is fine, and if you don't, it
isn't. Well, gosh. :)

But surely the whole point of type safety is that the compiler should yell
when you do something type-unsafe, yes?

But the compiler will not yell at this (fragment):

char c = 'A';
char *p = c;
void *q = p;
int *r = q;
*r = INT_MAX;

void * discards type safety.

After changing:

char *p = c;

to

char *p = &c;

which is what I think you meant, my main "compiler" still yells at me
with this warning:

int *r = q;
Info 826: Suspicious pointer-to-pointer conversion (area too small)

In practice, I'd look at that warning, then at the code, and just tell
my software engineer that that's a do-over, and to see me tomorrow
when she has it fixed :^)
 
R

Richard Heathfield

jaysome said:

After changing:

char *p = c;

to

char *p = &c;

which is what I think you meant,

Yes, that's correct.
my main "compiler" still yells at me
with this warning:

int *r = q;
Info 826: Suspicious pointer-to-pointer conversion (area too small)

That's nice. No, really! It's a great diagnostic, which goes above and
beyond the call of duty. But now hide the assignment in a function call (to
a function taking void * as its parameter), put the called function in a
different translation unit, and see if your compiler still manages to pick
it up.
 
R

Richard Bos

No. I am saying that you do not know if MAX(a,b) is a macro or a
function unless you examine the implementation.

Or you are able to assume that the programmer knew what he was doing and
uses ALL CAPITALS for macros, and for macros only. That's more or less
standard operating procedure; deviating from it is not a good idea.
MAX(++a,++b) is prefectly fine if it is a function

Technically. Stylistically, it goes against the grain.
By their very nature, function macros are defective and cause defects.

You could say the same thing about variadic functions - and more so
about scanf() - with about as much justification.

Assuming you mean Ariane 5, that's not quite a correct description. The
cause of those crashes was an overflow occuring in a conversion of a
64-bit floating point number to a 16-bit integer. That's a bad idea
whether you use macros to do it or inline functions.
Reusing bad software is worse than not reusing it.

On the older model, the software was not bad. The re-use on an
incompatible model caused the problem.
Wrong. It is used safely when you never input more bytes than the size
of the object.

To do this, however, you will need a safe room, a virgin computer, and
bondage gear. And perfect contgrol over your own typing fingers. (Point
in case: that typo in the previous sentence, introducing a single
character which could have overflown a buffer if it had involved gets(),
was not intentional.)
In a similar way, function macros are fatally flawed. They can be used
safely, but normal use is not safe.

Nonsense. gets() cannot be used safely without taking measures beyond
the ISO C Standard. Macros can be used with perfect safety using ISO C
alone.

Richard
 
R

Richard Heathfield

Richard Bos said:
(e-mail address removed) wrote:
<snip>

[Therac-25]
Reusing bad software is worse than not reusing it.

On the older model, the software was not bad. The re-use on an
incompatible model caused the problem.

Take this with a pinch of salt because my data source is Wikipedia, but it
appears at least possible that the software *was* bad, its bugs being
disguised by hardware interlocks on earlier versions of the Therac, which
were not present on the -25.

<snip>
 
R

Random832

2006-12-20 <[email protected]>,
#define MAX(a,b) ((a) > (b) ? (a) : (b))

unsigned foo = 1;
unsigned bar = 2;

unsigned biggest = MAX(++foo, ++bar);

It does not matter if they want the side effects or not. The side
effects cause a defect due to the nature of macros that prevents them
from being used safely.

That code is perfectly well-defined. At the end, biggest is 4, bar is 4, and
foo is 2. Nothing unsafe at all. Now, your problem is you assume that
the writer wants bar, and biggest, to be 3 rather than 4. But that's
entirely subjective.
I would remove function macros from the language.
Neither feature has any merit, considering that alternatives exist
which are superior in every way.

"function macros" aren't always used as a function. You could have one
that expands to a list of three things with commas and braces and use it
to help initialize a static struct array. How can inline functions do
that?
 
D

dcorbit

Richard Heathfield wrote:
[snip]
Right. And writing bad macros (or calling good macros in a bad way) is worse
than not writing them. That doesn't mean we can't write good macros, and
call them in a good way.

You can call function macros in a good way (carefully avoiding side
effects if you examine the full source of the macro) but you cannot
write them in a good way because they completely lack type safety and
do not produce the successful isolation that functions provide since we
pass by value.

There is no such thing as a function macro that is better than the same
thing written as an inline function. Using macros is lazy and stupid.
[snip]
 
R

Richard Heathfield

(e-mail address removed) said:
Richard Heathfield wrote:
[snip]
Right. And writing bad macros (or calling good macros in a bad way) is
worse than not writing them. That doesn't mean we can't write good
macros, and call them in a good way.

You can call function macros in a good way (carefully avoiding side
effects if you examine the full source of the macro) but you cannot
write them in a good way because they completely lack type safety and
do not produce the successful isolation that functions provide since we
pass by value.

I disagree. I'm not a huge fan of macros, but there are times when I
consider them to be useful and worthwhile, despite their lack of type
safety.
There is no such thing as a function macro that is better than the same
thing written as an inline function. Using macros is lazy and stupid.

I don't see why it's lazy. It actually takes more effort to write this:

#define BYTE(x) ((x) / CHAR_BIT)
#define BIT(x) ((x) % CHAR_BIT)
#define TEST_BIT(a, b) \
(!!(((a)[BYTE(b)]) & (1 << (BIT(b)))))

than this:

int byte(size_t b)
{
return b / CHAR_BIT;
}

int bit(size_t b)
{
return b % CHAR_BIT;
}

int test_bit(unsigned char *a, size_t b)
{
return !!(a[byte(b)] & (1 << bit(b)));
}

because, even though the latter is longer, it's considerably easier to type.

As for "stupid", well, that's a matter of opinion.
 
K

Keith Thompson

#define MAX(a,b) ((a) > (b) ? (a) : (b))

Good, the use of all-caps warns the user that it's a macro.
unsigned foo = 1;
unsigned bar = 2;

unsigned biggest = MAX(++foo, ++bar);

It does not matter if they want the side effects or not. The side
effects cause a defect due to the nature of macros that prevents them
from being used safely.

It's *possible* to use it unsafely. It's also possible to use it
safely. Part of being a good C programmer is knowing that macros can
cause problems if you invoke them with arguments that have side
effects.
Have you ever heard of the Arianne failure? Type safety.

Yes I have. The major problem IIRC was the re-use of the software
for, I think, the Ariane 4 in the Ariane 5 without re-testing for the
new environment. I'm not sure what that has to do with the current
discussion.

[...]
If I had my way, min(a,b) and max(a,b) would be removed from the
standard library headers.

[F/X: waves magic wand] Since it is the season of gifts, Dann, your wish is
granted. Not only have I removed min and max from the standard library
headers for you, but I have applied this change retroactively, so that it
shall be as if they had *never* been part of the standard library headers.

Right, that's C++ with the header defect. Lots of C compilers mimic
it, though.

<OT>C++ has min() and max() defined via type-safe templates.</OT>

A conforming C implementation cannot declare "min" or "max" in any
standard header.
 
K

Keith Thompson

No. I am saying that you do not know if MAX(a,b) is a macro or a
function unless you examine the implementation.

By convention, macro names are in all-caps. This convention is not
universally followed, but I'd certainly assume that MAX() is a macro
-- and if it isn't, I'd complain to the programmer who decided to give
it that name.
MAX(++a,++b) is prefectly fine if it is a function and we do not know
if it is OK if it is a macro.

Right, so the *documentation* had better mention that it's a macro.
 
D

dcorbit

Random832 said:
2006-12-20 <[email protected]>,


That code is perfectly well-defined. At the end, biggest is 4, bar is 4, and
foo is 2. Nothing unsafe at all. Now, your problem is you assume that
the writer wants bar, and biggest, to be 3 rather than 4. But that's
entirely subjective.

In other words, it does not work like a function in this example and
produces 'odd' results.

Because the conditional is a sequence point, that particular one does
not cause undefined behavior, but something as simple as:
#define SQUARE(x) ((x)*(x))
unsigned x = 5;
unsigned y = SQUARE(x++);
does produce undefined behavior.

In each case for those samples provided the macros did something odd.
"function macros" aren't always used as a function. You could have one
that expands to a list of three things with commas and braces and use it
to help initialize a static struct array. How can inline functions do
that?

I am not opposed to macros that are not used as functions, unless badly
written.
 
K

Keith Thompson

Can you please suggest that in what cases should a macro be
preferred over inline function and viceversa ? Is there any case where
using a macro will be more efficient as compared to inline function ?
[...]

#define MAX(a,b) ((a) > (b) ? (a) : (b))
[...]
char *s0,
*s1,
*s2; [...]
s0 = "My name is Skinner The Grinner.";
s1 = "I am a foo bird but I can't fly";
s2 = MAX(s1, s0);
[...]

This invokes undefined behavior by using the relational operator "<"
on pointers to different objects.
 
K

Keith Thompson

There is no such thing as a function macro that is better than the same
thing written as an inline function. Using macros is lazy and stupid.

What if you're using a compiler that doesn't implement inline functions?
 
D

dcorbit

Keith said:
What if you're using a compiler that doesn't implement inline functions?

1. Upgrade your compiler. GCC is fairly ubiquitous across most
platforms, for instance.
2. Write the inline expressions as actual inline expressions.
3. Suffer the function overhead (probably except for very rare cases
it won't matter).
4. Use function macros and hope for the best.

I will admit to having written and used function macros. That having
been said, it was lazy and stupid of me.
 
R

Richard Bos

1. Upgrade your compiler. GCC is fairly ubiquitous across most
platforms, for instance.

But not all.
2. Write the inline expressions as actual inline expressions.

Again and again and again? That's bad programming. It is, for starters,
harder to maintain, and easier to make a typo.
4. Use function macros and hope for the best.

Bravo. The most sane solution.
I will admit to having written and used function macros. That having
been said, it was lazy and stupid of me.

*Shrug* I think you're being stupid now, not then.

Richard
 

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,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top