J
Julie
David said:Not all macros are evil.
Example?[/QUOTE]
#define NULL 0
#define offsetof(s,m) (size_t)&(((s *)0)->m)
David said:Not all macros are evil.
#define NULL 0
#define offsetof(s,m) (size_t)&(((s *)0)->m)
Ioannis said:And some nicest alternatives:
const int NULL=0;
That appears to not work. You cast 0 to a struct/class pointer of s *, you
dereference that null pointer it to access a data member m which is illegal,
and then you get its address and cast it to size_t.
Example?
Julie said:How about some justification as to why const is 'nicer' than #define, other
than rhetoric.
This is how it is implemented in my stddef.h -- the particulars are
implementation-defined, however the behavior is well-defined.
I've provided two examples of macros that satisfy his question.
Ioannis said:That's a nice detail to quibble about.
And yours above is not evil?
Julie said:This is how it is implemented in my stddef.h -- the particulars are
implementation-defined, however the behavior is well-defined.
Julie said:Not quibbling about.
Take a look at the standard library regarding offsetof. The behavior is well
defined. How it is implemented, is implementation defined.
Forget about the actual implementation that I posted for a minute, and consider
the macro behavior. It is useful, well-defined, and a valuable component of
the standard library, and it is a macro.
The notion that "all macros are bad" is more dangerous than the potential
misuse of macros.
Chew on that for a while, once you get out of the box.
Kevin said:You can't get well-defined out of implementation-defined. The best you
can hope for is more implementation defined.
However, in this case there is no implementation-defined behavior. It is
completely undefined.
Julie said:When you pick pieces out of context, you can make any argument that you want.
I said that the _particulars_ are implementation defined (meaning the
underlying implementation), the _behavior_ is well defined.
Contrary to your belief, this is the case, and is entirely possible.
The previous poster requested an example of a 'non-evil' macro, and I provided
that.
Kevin said:If you defined that macro yourself and used it, the behavior would NOT
be defined. You are free to use the library-supplied 'offsetof' macro,
and it will be well-defined, but that's not the same. An implementation
would be perfectly within its rights to (for example) crash on your
macro, even if it's identical to the standard library version.
If you rely on implementation-defined behavior, you can't do better than
implementation-defined. But that's not particularly relevant, since
there was no implementation-defined behavior in the example.
'Evil' is a technical term in C++ circles. It doesn't mean "not to be
used under any circumstances". This is in the FAQ.
Do you agree that the offsetof() macro is an example of a 'non-evil' macro or
not?
Ioannis Vranos said:When we say avoid the use of macros, is because the use of macros is
inherently dangerous,
it may behave in an unexpected way, and bugs caused by
macro substitution of a macro defined in a header file which used in another
header file, which is used in our code are of the most difficult to trace.
C++ provides a superior alternative to macros (and void *s by the way) ,
templates. They are compile time checked and type safe.
Well it is apparent that we will stick to our own opinions.
I am not in the box, i am in the hug of my LCD monitor.
Paul Mensonides said:If you're going to make unilateral statements such as this, you need to actually
back it up with specifics instead of repeating prejudicial generalizations.
Macros are *not* inherently dangerous. Certain *uses* of macros are dangerous
and have other pitfalls, but by no means does this extend to the general notion
of macros. This extends to other constructs as well that have, at times, even
greater pitfalls in C++. The way to deal with these pitfalls is through idioms
and techniques that are not enforced by the language itself except in some cases
through diagnostics (and sometimes with no diagnostic required by the standard).
The preprocessor, and the macro mechanism in particular, is simply easier to
target as an isolated entity. The pronouncement that "macros are evil" is
merely an act of people being to lazy to define exactly what sorts of usages are
or are not evil with respect to macros. It is as ridiculous as saying that
templates are evil because undetected POI issues exist.
Here your making another gross oversimplification. C++ provides a superior
alternative to using macros to define type/value generic constructs (such as
classes and functions) and inline functions (and sometimes constants). That
doesn't even come close to covering the range of uses of macros.
I totally agree with this. Specifically, notions like the above are dangerous
because they show a lack of understanding and thought about when and where which
tool should be applied. It shows a serious lack of lateral thinking and logical
deduction.
A statement like "macros are inherently dangerous" comes straight out of the
box.
Consider Boost, which contains a great deal of out-of-the-box thinking
resulting in some incredible libraries that push the boundaries of all
previously existing design technique. And then consider further, that many of
those libraries are generated *with macros that have never caused a name clash
despite the relatively widespread use of Boost*. I'm not saying that macros are
the end-all-and-be-all, and I'm not saying that many uses (if not *most* uses in
practice) are not dangerous. What I am saying is that there are both good uses
and bad uses--just like with every other language feature or intersection of
features. Anything else is the result of people being too lazy to actually pin
down the problems or naivety caused by blind application of guidelines that are
themselves a product of previous laziness.
Ioannis Vranos said:With only few exceptions like inclusion guards, you can do whatever you can
do with macros with templates. So what remains at the end are the dangerous
uses.
So do you think macros should be used in every day's code?
I never said that "macros are evil". But (obviously) in the contrary of you,
i consider a good practice to try avoid using macros as much as it is
possible.
And also i never said the above. What i said is
"We must try to avoid using macros completely (mainly by using templates),
with very few exceptions that this can't be done (mainly the #ifndef
stuff)."
Well i agree. But i like to term the meaning of your phrase
"What I am saying is that there are both good uses and bad uses--just like
with every other language feature or intersection of features."
as
"We must avoid using macros where possible".
No, you can't. For instance, you cannot generate the source code of templates
with templates, but you can with macros. You cannot generate a set of typesafe
overloaded functions with arity ranging from zero to any conceivable number of
parameters with templates, but you can with macros.
Paul Mensonides said:The two are quite different, and the bad uses of macros do not outweight their
good uses enought (if they do at all) to draw an equivalence between the two
statements. According to your logic, you should also be saying, "We must avoid
using templates where possible." I.e. just because something *can* be used
poorly, doesn't mean that something cannot be used well, and, similarly, just
because something *can* be used well, doesn't mean that something cannot be used
poorly. In the case of templates, finding template-related bugs can be far far
worse than anything related to macros at all. Moral of the story, you cannot
condense good programming to a set of near black-and-white guidelines.
David Harmon said:On Sat, 17 Apr 2004 21:07:07 -0700 in comp.lang.c++, "Paul Mensonides"
Oh, that is all sophistry. You are saying basically, that you cannot
use templates in the identical fashion that you use macros. Well, so
what? The point is that you can accomplish the reasonable purpose
formerly served by macros, with templates, consts, and other C++
constructs that offer the advantages of being integrated with the
language. That you cannot perform exactly the same gyrations on the way
to getting there is not a bug, it's a feature.
Paul Mensonides said:No, it isn't sophistry. It's simply a gross reduction of solutions to issues of
which you apparently have no conception. I'm not talking about generating
functions or classes with varying types, and I'm certainly not advocating that
macros be used for such a purpose without a really good reason--that is what
templates are for. I'm talking about generating source code, be it templates or
overloaded functions or whatever (a lexical analyzer, perhaps) that is
impossible to achieve otherwise without an external code generator or with
excessive manual copying. The first requires another build step--which is
terrible in a library context--and the second dramatically increases the number
of maintenance points.
The point is that you can accomplish many *but by no means all* purposes
formally served by macros. I'm not disagreeing that there are better solutions
to many things that macros were used for at one time. It isn't a question of
getting to the same place a different way; instead, it is that the destination
is quite different. One way to look at it is that the preprocessor is to
templates as templates are to classes and functions. (That certainly doesn't
summarize the entire field, but it does summarize a large portion of it.)
Regarding your "bug/feature" statement... You are certainly correct that
templates are a great feature for what they are intended to do. The same
extends to constant variables vs. macros, but to a slightly lesser degree. I'm
not arguing that, and I never will. What I am arguing is that statements such
as "macros are evil" or "macros are inherently dangerous" (which are both common
statements) are prejudicial generalizations that simply aren't true. Macros are
not evil, certain usages of them are. Macros are not inherently dangerous,
certain uses of them are. That is no different than any other language feature
or intersection of features. The only difference is that many have been too
brainwashed by statements like the above to investigate the cause-and-effect of
feature intersections within the preprocessor (within macro expansion in
particular) and feature intersections between the preprocessor and the language
proper--like they have with the underlying language.
collision areAs an aside, the core language is no more protected from name clashes than the
preprocessor. Namespaces serve to classify and organize names, but they do not,
at a language level, protect them. The only things that stop name
Ioannis Vranos said:And something most do not know is that the use of a global namespace
declaration is not good. E.g.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// ..
}
is bad style. For accuracy it is an attempt to defeat the namespace system.
That's why a typical C++ standard library implementation of <stdio.h> is (or
better should be):
--- stdio.h ---
#include <cstdio>
using std:rintf;
using std::sprintf;
// ...
using std::scanf;
// etc
--- end of C++ stdio.h ---
I'm talking about generating source code, be it templates or
overloaded functions or whatever (a lexical analyzer, perhaps) that is
impossible to achieve otherwise without an external code generator or with
excessive manual copying. The first requires another build step--which is
terrible in a library context--and the second dramatically increases the number
of maintenance points.
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.