Dan Pop
Michael Mair
#define SWAP(m,n) \
(tmp=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=tmp)
tmp must be provided from the outside -- this is a possible
source of error.
Not any more than having buys_for passed from outside. If there is no
good tmp in scope, the compiler will complain, just as it complains if
there is no good buys_for in scope.
Yep, the thing is that I had enough "fun" with people using
"tmp" or similar names in macros and wondering why it went wrong
-- they happened to have a tmp in scope but not the one they would
have needed. I would be happier with "buys_for_tmp".
Using a macro without understanding its needs and limitations is just
one of the many stupid things fools do. No point in trying to write code
that even a fool could maintain: the fool will always defeat your
attempts at being foolproof.
either pass tmp, too:
#define SWAP(m,n,tmp) \
((tmp)=buys_for[m],buys_for[m]=buys_for[n],buys_for[n]=(tmp))
No point in complicating the interface of SWAP.
This is just an intermediate step; I really should have commented
more on this and the following. However, from here you obtain easily
the general SWAP you mention below by
#define SWAP(a,b,tmp) \
((tmp)=(a),(a)=(b),(b)=(tmp))
What do you need the "protecting" parentheses for?
and calling, e.g., SWAP(buys_for[m],buys_for[n],tmp);
Which is defeating the purpose of SWAP: to simplify the code using it,
making it easier to read and understand. For no redeeming advantages.
It should have been obvious to anyone that it was not meant to be a
general purpose swapping macro, but one tailored to the needs of the
application.
or provide it here:
#define SWAP(m,n) \
{int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;}
Read the FAQ to see why this is not a good macro definition.
If you want to educate a newbie, don't teach him bad things.
Do you refer to the definition as
#define SWAP(m,n) do {\
int tmp=buys_for[m]; buys_for[m]=buys_for[n]; buys_for[n]=tmp;\
} while(0)
in order to be able to fake a statement (and have no trouble with
if and similar, see FAQ 10.4) or to the fact that I am now stuck with
a type?
The former can be considered a bug, while the latter is merely a design
flaw. You could argue that your original version was good enough for this
particular application, but you seemed to have a more ambitious goal in
mind, hence my objections.
Granted.
In this case, I wanted to make it compatible.
However, I am more or less thinking of inline functions. Here,
I might still call it SWAP() if it were the only swap function
because I am more or less using a "macro-like function" ;-),
so I call it whichever may be clearer.
Wrong! You're merely obfuscating the things. Macro names are spelled in
upper case to warn the reader that something that looks like a function
call doesn't have the semantics of a function call. If you start writing
genuine function names in upper case, this very important message is lost.
Inline or not, a function call is not a macro invocation.
{
int tmp = *a;
*a = *b;
*b = tmp;
}
and pass &buys_for[m], &buys_for[n] to SWAP().
Source code overheads, execution time overheads for no redeeming merits.
The original version is good enough (actually the best) for this
program and it is completely pointless to judge it in a wider context.
Er, right. I think you had a similar discussion with the OP about the
random numbers.
Exactly. The *simplest* solution that is entirely appropriate to the
problem should be always preferred. I wrote the program to illustrate
the description of an algorithm, not to teach anyone about how to write
Monte Carlo simulations or the "best" swapping macro.
I rather like having the right types and being sure that everything
works as intended.
It would be nice if C provided such certainties...
So, I go for inline functions whenever _I_ think
it is more sensible than using a macro.
Inline functions are not an option if you have to write portable C code
today.
You can of course be of different opinion.
The above is not a matter of opinion, it is a matter of fact.
Yes, of course. You also could just have pointed this out above where
you criticized the same interface for the non-general version as too
complicated.
If it's non-general, there is no point in keeping it any more complicated
than *strictly* needed. In my example above, it is the generality that
justifies the complication in the interface. I wouldn't use such a macro
in any program where I need to swap only variables of one type.
Well, I would have liked to see some of the deprecated stuff outlawed.
Me too, but they decided that 10 years was not time enough for people to
clean up the codes they maintain.
At least we are rid of implicit int.
Which was NOT deprecated by C89, BTW.
As for the empty parameter list: There was a discussion recently about
possible pitfalls if main() is called again from "within".
True, but recursively calling a main defined with no parameters is not
something I consider sane. The other case may be open to discussion, but
the C++ people decided that it is sa[nf]er to outlaw it.
Because there is no visible call to main in the whole program, I don't
bother writing a prototype definition when there are no parameters. All
other parameterless functions do get their prototype definitions, because
they will be called from inside the program, with a prototype declaration
in scope. I wonder if the standard forcing me to change this habit will
be drafted during my lifetime