Index a #define string

P

Paul Mensonides

Ioannis said:
I think it is a matter of views. I did not say to remove macros from
the language but i do not consider the macros matter as a balanced
issue - that there are as many good uses as bad uses. Macros are not
to be used in daily application programming.

And that is a wrong assessment. Macros are not to be used when the use of
something else is better--and vice versa. Whether it is library code or
application code is irrelevant. You cannot simplify it that easily.
For example i program C++ applications for .NET and i see no need to
use macros. On the other hand you seem to work in libraries area and
you use macros daily to get the job done. So perhaps the "default"
for each one of us is different. I can understand the use of macros
in libraries, but still even in that case my "default" would not be
to use macros but only where i can't do work without them.

I agree that the good uses of macros appear more often in library code than in
application code. However, there is no universally clear distinction between
what should be library code and what should be application code. And even if
there was, good uses for macros in application code still appear often enough
that such a generalization is invalid. It isn't that I disagree with you
regarding the use of templates, constant variables, inline functions, etc.. I
disagree that those things even come close to encompassing the totality of macro
use--many of which you probably aren't aware of. In essence, the guideline that
you espouse is invalid because it is too broad and needs to be broken down into
constituent guidelines which actually *are* valid. Otherwise, you propogate the
status quo of prejudice-oriented programming which avoids the singlular problem
of macro name collision while simultaneously producing suboptimal code that
likely includes maintenance nightmares. Use macros when macros are the best
option to do a thing, otherwise don't--no prejudice involved, but it implies
that you actually have to *know* what is good or bad and why. There is nothing
wrong with that at all--it is the antithesis of laziness.
There are things one can do only with macros, and i would use macros
only to do those.

What about things that can be done much easier and much more efficiently in
terms of both run-time performance and maintenance?
Some quotes from TC++PL 3:


Page 10:

"The template facility was primarily designed to support statically
typed containers (such as lists, vectors, and maps) and to support
elegant and efficient use of such containers (generic programming). A
key aim was to reduce the use of macros and casts (explicit type
conversion)."

Yes, and for that purpose (and others) templates are great.
Page 14:

"1.6.1 Suggestions for C Programmers

The better one knows C, the harder it seems to be to avoid writing
C++ in C style, thereby losing some of the potential benefits of C++.
Please take a look at Appendix B, which describes the differences
between C and C++. Here are a few pointers to the areas in which C++
has better ways of doing something than C has:

[1] Macros are almost never necessary in C++.

Wrong, for a variety of reasons. The most ironic of them is that various C++
implementations differ far more radically than various C implementations.
Use const (§5.4) or enum
(§4.8) to define manifest constants,

Most of time, yes--unless it is needed by the preprocessor for a good reason.
In such a case, it should be mirrored:

#define LIBRARY_XYZ 10

namespace library {
const int xyz = LIBRARY_XYZ;
}
inline (§7.1.1) to avoid function
calling overhead,

Yes, except in very special cases where you actually *do* know better than the
compiler.
templates (Chapter 13) to specify families of
functions and types, and namespaces (§8.2) to avoid name clashes."

Namespaces don't avoid name clashes per se. They provide a means to structure
and classify names. That indirectly avoids name clashes by effectively
increasing the length of the relevant names. That's a minor point, however, and
otherwise I agree.
Page 160:

"7.8 Macros

Macros are very important in C but have far fewer uses in C++.

Along certain lines, yes. Along other lines, the exact opposite is true.
The
first rule about macros is: Don't use them unless you have to. Almost
every macro demonstrates a flaw in the programming language, in the
program, or in the programmer.

The "first rule about macros" is wrong. It should be, don't use them when there
is a superior alternative within the language proper--where "superior" means the
total set of all possible ways in which something can be superior or inferior
(some of which are subjective, some of which are not).

Many macros do indeed demonstrate flaws in the programming language--one of them
being the lack of power that macros have (compared to other macro mechanisms).
This also represents a broad class of language deficiencies that are never going
to change. Some will, yes, but otherwise, so what? Flaws in the program and in
the programmer obviously exist, and many times the use of macros demonstrates
that--as does the use of many combinations of language elements. In any case,
the above is true if "almost every macro" means almost every existing macro
currently in existence. The above is not true if "almost every macro" is
supposed to mean "almost every possible use of macros".
Because they rearrange the program
text before the compiler proper sees it, macros are also a major
problem for many programming tools.

First, macros do not rearrange the program "text", they rearrange the program's
preprocessing tokens within a translation unit. Second, that is the fundamental
reason why the preprocessor is such a powerful tool in certain types of
situations. That is what provides both the power and the danger of the
preprocessor, and consequently (as a generalization) where and when the use of
macros can be good.
So when you use macros, you
should expect inferior service from tools such as debuggers,
crossreference tools, and profilers.

Wrong, or at least, not specific enough. This is entirely dependant on how
macros are used and for what purpose.
If you must use macros, please
read the reference manual for your own implementation of the C++
preprocessor carefully and try not to be too clever. Also to warn
readers, follow the convention to name macros using lots of capital
letters."

Absolutely. In addition, you should always undefine macros that are used only
locally.
Page 161:

"Using macros, you can design your own private language. Even if you
prefer this ''enhanced language'' to plain C++, it will be
incomprehensible to most C++ programmers.

The reference here is making C++ look like, for example, Pascal. I'm definitely
not advocating doing that--along with the reason given, you'd be trading a
concise language for an extremely verbose one. ;)
Furthermore, the C
preprocessor is a very simple macro processor. When you try to do
something non-trivial, you are likely to find it either impossible or
unnecessarily hard to do.

Which is why you have libraries that specialize in this sort of thing.
The const, inline, template, and namespace
mechanisms are intended as alternatives to many traditional uses of
preprocessor constructs.

And for many purposes, they are great alternatives. As I've said before, in
nearly all situations, these are better alternatives to their corresponding
macro formulations.
Page 163:

"7.9 Advice

[1] Be suspicious of non-const reference arguments; if you want the
function to modify its arguments, use pointers and value return
instead; §5.5. [2] Use const reference arguments when you need to
minimize copying of arguments; §5.5.
[3] Use const extensively and consistently; §7.2.
[4] Avoid macros; §7.8."

Which just illustrates Bjarne's well-known prejudice against macros resulting
from many of the traditional uses of them. So what?

Regards,
Paul Mensonides
 
P

Paul Mensonides

David said:
On Sun, 18 Apr 2004 13:55:36 -0700 in comp.lang.c++, "Paul Mensonides"


Lexical analyzer? Show me a C preprocessor implementation of anything
to compare with Joel de Guzman's Spirit parser template library.
http://spirit.sf.net

You want to know what is really funny about that? Joel de Guzman uses the
preprocessor in Spirit and Fusion for exactly the kind of stuff that I'm talking
about.

Regards,
Paul Mensonides
 
I

Ioannis Vranos

Ioannis Vranos said:
Namespaces do not exist to protect from name collisions. Namespaces are
the


Errata:

Namespaces do not exist to protect from general name collisions. Namespaces
are the






Regards,

Ioannis Vranos
 
I

Ioannis Vranos

Paul Mensonides said:
Which just illustrates Bjarne's well-known prejudice against macros resulting
from many of the traditional uses of them. So what?


So we reach nowhere. :)






Regards,

Ioannis Vranos
 
P

Paul Mensonides

Ioannis said:
"Paul Mensonides" <[email protected]> wrote in message
Macros must be avoided where possible. In an effort to not hurt your
feelings we can rephrase that "Use macros only when needed".

You're not hurting my feelings, you're simply wrong and extremely naive.
Choose
whatever fits you better, they are both the same.

No, they are not. You simply have no concept of the things that I am talking
about because they are so far above your level of expertise in the fields in
which they apply.
And C++ is not C,
you may have been a C programmer for some long time and have done a
lot of real and excellent work with macros, but C++ is not C and in
most cases the language provides superior alternatives.

No, in *many* cases the language provides superior alternatives. What's amazing
here is your complete lack of willingness to accept that you don't know
everything. You think that you know what I'm talking about, but apparently you
have no idea. Otherwise, you wouldn't be saying that the functionality can be
replicated with, e.g., templates, because they can't.
On the other hand, if you *still* program in C and you use macros,
then what we discuss here does not apply.

I'm not talking about C, and the context that applies to what I'm saying applies
far more in C++ (though it still does in C).
Namespaces do not exist to protect from name collisions. Namespaces
are the implementation of the modular programming paradigm

Which is exactly what I said, believe me, I know what namespaces are.

Regards,
Paul Mensonides
 
C

Christopher Benson-Manica

Kevin Goodsell said:
'Evil' is a technical term in C++ circles. It doesn't mean "not to be
used under any circumstances". This is in the FAQ.

Indeed, and I'm sorry I didn't consider that FAQt (to make a pun, or
something) before making my claim.
 
C

Christopher Benson-Manica

David Harmon said:

This is belated, and I'm sure you won't like it, but some time ago the
following appeared on comp.lang.c:

#define YEAR ((((__DATE__ [7] - '0') * 10 + (__DATE__ [8] - '0')) * 10 \
+ (__DATE__ [9] - '0')) * 10 + (__DATE__ [10] - '0'))

#define MONTH (__DATE__ [2] == 'n' ? 1 \
: __DATE__ [2] == 'b' ? 2 \
: __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 3 : 4) \
: __DATE__ [2] == 'y' ? 5 \
: __DATE__ [2] == 'n' ? 6 \
: __DATE__ [2] == 'l' ? 7 \
: __DATE__ [2] == 'g' ? 8 \
: __DATE__ [2] == 'p' ? 9 \
: __DATE__ [2] == 't' ? 10 \
: __DATE__ [2] == 'v' ? 11 : 12)

#define DAY ((__DATE__ [4] == ' ' ? 0 : __DATE__ [4] - '0') * 10 \
+ (__DATE__ [5] - '0'))

#define DATE_AS_INT (((YEAR - 2000) * 12 + MONTH) * 31 + DAY)

It's nothing if not ingenious :)
 
X

Xenos

Christopher Benson-Manica said:
David Harmon <[email protected]> spoke thus:
#define MONTH (__DATE__ [2] == 'n' ? 1 \
: __DATE__ [2] == 'b' ? 2 \
: __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 3 : 4) \
: __DATE__ [2] == 'y' ? 5 \
: __DATE__ [2] == 'n' ? 6 \
: __DATE__ [2] == 'l' ? 7 \
: __DATE__ [2] == 'g' ? 8 \
: __DATE__ [2] == 'p' ? 9 \
: __DATE__ [2] == 't' ? 10 \
: __DATE__ [2] == 'v' ? 11 : 12)
how does this work for "january" and "june"?
 
D

Default User

David said:
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.

Here's a question, not designed to be argumentative or contradictory but
rather a genuine request for information. What about macros similar to
assert(), that provide error-checking at a certain level of development
and then are removed in their entirety (test included) at another? Is
there another way to accomplish this without preprocessor constructs?



Brian Rodenborn
 
X

Xenos

Default User said:
David Harmon wrote:

Here's a question, not designed to be argumentative or contradictory but
rather a genuine request for information. What about macros similar to
assert(), that provide error-checking at a certain level of development
and then are removed in their entirety (test included) at another? Is
there another way to accomplish this without preprocessor constructs?



Brian Rodenborn

I believe this can be done with specialized templates. I think the BOOST
library has an example of this.
 
I

Ioannis Vranos

Default User said:
Here's a question, not designed to be argumentative or contradictory but
rather a genuine request for information. What about macros similar to
assert(), that provide error-checking at a certain level of development
and then are removed in their entirety (test included) at another? Is
there another way to accomplish this without preprocessor constructs?


I do not think there can be an alternative wth the same properties, but we
are not talking about banning the macro mechanism from the language, nor not
using the macro standard library facilities. But to avoid creating macros,
when possible.






Ioannis Vranos
 
C

Christopher Benson-Manica

Xenos said:
#define MONTH (__DATE__ [2] == 'n' ? 1 \
: __DATE__ [2] == 'b' ? 2 \
: __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 3 : 4) \
: __DATE__ [2] == 'y' ? 5 \
: __DATE__ [2] == 'n' ? 6 \
: __DATE__ [2] == 'l' ? 7 \
: __DATE__ [2] == 'g' ? 8 \
: __DATE__ [2] == 'p' ? 9 \
: __DATE__ [2] == 't' ? 10 \
: __DATE__ [2] == 'v' ? 11 : 12)
how does this work for "january" and "june"?

It doesn't, does it? I'm not sure whether it was the poster's fault
or my failure to copy it correctly, but I can fix it:

#define MONTH (__DATE__ [2] == 'n' ? (__DATE__ [1] == 'a' ? 1 : 6) \
: __DATE__ [2] == 'b' ? 2 \
: __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 3 : 4) \
: __DATE__ [2] == 'y' ? 5 \
: __DATE__ [2] == 'l' ? 7 \
: __DATE__ [2] == 'g' ? 8 \
: __DATE__ [2] == 'p' ? 9 \
: __DATE__ [2] == 't' ? 10 \
: __DATE__ [2] == 'v' ? 11 : 12)

Nice catch.
 
D

Default User

I believe this can be done with specialized templates. I think the BOOST
library has an example of this.


Could you be a bit more specific?



Brian Rodenborn
 
D

David Harmon

Lexical analyzer? Show me a C preprocessor implementation of anything
to compare with Joel de Guzman's Spirit parser template library.
http://spirit.sf.net

You want to know what is really funny about that? Joel de Guzman uses the
preprocessor in Spirit and Fusion for exactly the kind of stuff that I'm talking
about.[/QUOTE]

Joel does not use the preprocessor to implement a lexical analyser or
anything of the sort. Or perhaps you are ready to stop beating around
the bush and actually say what you are talking about. Spirit and for
that matter the rest of Boost uses the preprocessor mainly:

1. As a hackish work-around for various broken and incomplete
implementations of C++, mainly of templates. Nobody would deny that if
your implementation is broken, the preprocessor may be the work-around
you are left holding.

2. Debugging, which makes sense as debugging is closely tied to
program source code and _not_ to what you are otherwise trying to
implement. This often takes the form of inserting __FILE__ __LINE__ or
a fragment from the source into a debug string using the # preprocessor
operator, with the fact that a macro is doing it being almost
incidental.

I do indeed approve of the assert() macro and similar in the context of
C++ debugging, despite its hazards. Of course people like Walter Bright
would disagree, and in his D language assert() is implemented as a
compiler facility since there is no preprocessor as such remaining.
http://www.digitalmars.com/D/
 
P

Paul Mensonides

David said:
You want to know what is really funny about that? Joel de Guzman
uses the preprocessor in Spirit and Fusion for exactly the kind of
stuff that I'm talking about.

Joel does not use the preprocessor to implement a lexical analyser or
anything of the sort. Or perhaps you are ready to stop beating around
the bush and actually say what you are talking about. Spirit and for
that matter the rest of Boost uses the preprocessor mainly:[/QUOTE]

How about:

spirit/core/non_terminal/rule.hpp
spirit/core/non_terminal/impl/rule.ipp
spirit/dynamic/select.hpp
spirit/dynamic/impl/switch.ipp
spirit/fusion/sequence/make_tupe.hpp
spirit/fusion/sequence/tie.hpp
spirit/fusion/sequence/tuple20.hpp
spirit/fusion/sequence/tuple30.hpp
spirit/fusion/sequence/tuple40.hpp
spirit/fusion/sequence/tuple50.hpp
spirit/fusion/sequence/tuple_forward.hpp
spirit/fusion/sequence/detail/generate.hpp
spirit/fusion/sequence/detail/tuple10.hpp
spirit/fusion/sequence/detail/tuple_builder.hpp
spirit/fusion/sequence/detail/tuple_macro.hpp
spirit/utility/grammar_def.hpp

All of those files use preprocessor metaprogramming to generate code--and that
is just Spirit/Fusion. Other examples include Boost.Function, Boost.Lambda,
Boost.MPL, Boost.Python, Boost.Test, Boost.Type_Traits, and Boost.Variant.
Further, those aren't even counting things that use the preprocessor in
extremely simple ways to generate code.

As you say below, Boost uses the preprocessor to deal with broken compilers and
minimal debugging, but that is not even close to the whole story.

Despite your accusation, I haven't been beating around the bush. I have been
saying exactly what I mean: the preprocessor is used, for example, to *generate*
source code for the express purpose of minimizing maintenance points and
avoiding repetitive coding. This is beyond the scope of what templates or other
"language proper" mechanisms can do. Period.

Regards,
Paul Mensonides
 
M

Michiel Salters

Christopher Benson-Manica said:
David Harmon said:

This is belated, and I'm sure you won't like it, but some time ago the
following appeared on comp.lang.c:

#define YEAR ((((__DATE__ [7] - '0') * 10 + (__DATE__ [8] - '0')) * 10 \
+ (__DATE__ [9] - '0')) * 10 + (__DATE__ [10] - '0'))

#define MONTH (__DATE__ [2] == 'n' ? 1 \
: __DATE__ [2] == 'b' ? 2 \
: __DATE__ [2] == 'r' ? (__DATE__ [0] == 'M' ? 3 : 4) \
: __DATE__ [2] == 'y' ? 5 \
: __DATE__ [2] == 'n' ? 6 \
: __DATE__ [2] == 'l' ? 7 \
: __DATE__ [2] == 'g' ? 8 \
: __DATE__ [2] == 'p' ? 9 \
: __DATE__ [2] == 't' ? 10 \
: __DATE__ [2] == 'v' ? 11 : 12)

#define DAY ((__DATE__ [4] == ' ' ? 0 : __DATE__ [4] - '0') * 10 \
+ (__DATE__ [5] - '0'))

#define DATE_AS_INT (((YEAR - 2000) * 12 + MONTH) * 31 + DAY)

It's nothing if not ingenious :)

With the MONTH fix incorporated, you can do even do useful things:
---------------------------------------
#include <cassert>

#define UNIQUE_NAME( Y,M,D ) ReviewBefore##_##Y##_##M##_##D##_##line
#define REVIEW_DATE( YYYY, MM, DD ) (((YYYY - 2000) * 12 + MM) * 31 +
DD)
#define COMPILE_DATE (((YEAR - 2000) * 12 + MONTH) * 31 +
DAY)

#define REVIEW_BEFORE( YYYY, MM, DD ) \
static const struct UNIQUE_NAME(YYYY,MM,DD)##__LINE__ {
UNIQUE_NAME(YYYY,MM,DD)##__LINE__() { \
assert( COMPILE_DATE < REVIEW_DATE(YYYY, MM, DD) ); \
} } UNIQUE_NAME(YYYY,MM,DD)##__LINE__

#define REVIEW_BEFORE_STMT( YYYY, MM, DD ) \
assert( COMPILE_DATE < REVIEW_DATE(YYYY, MM, DD) )
---------------------------------------
Example Usage:

REVIEW_BEFORE( 2005, 01, 01 ); // Form 1:global

int main(int argc, char** argv)
{
REVIEW_BEFORE_STMT( 2004, 01, 01 ); // Form 2: in function
}

Now your code has an expiry date :)

Regards,
Michiel Salters
 
C

Christopher Benson-Manica

Michiel Salters said:
int main(int argc, char** argv)
{
REVIEW_BEFORE_STMT( 2004, 01, 01 ); // Form 2: in function
}
Now your code has an expiry date :)

Cute! And ingenious! Although some might argue that such code should
expire immediately ;)
 
J

Julie

David Harmon wrote:
[snip]
Joel does not use the preprocessor to implement a lexical analyser or
anything of the sort. Or perhaps you are ready to stop beating around
the bush and actually say what you are talking about. Spirit and for
that matter the rest of Boost uses the preprocessor mainly:

1. As a hackish work-around for various broken and incomplete
implementations of C++, mainly of templates. Nobody would deny that if
your implementation is broken, the preprocessor may be the work-around
you are left holding.

2. Debugging, which makes sense as debugging is closely tied to
program source code and _not_ to what you are otherwise trying to
implement. This often takes the form of inserting __FILE__ __LINE__ or
a fragment from the source into a debug string using the # preprocessor
operator, with the fact that a macro is doing it being almost
incidental.

I do indeed approve of the assert() macro and similar in the context of
C++ debugging, despite its hazards. Of course people like Walter Bright
would disagree, and in his D language assert() is implemented as a
compiler facility since there is no preprocessor as such remaining.
http://www.digitalmars.com/D/

Those all sound like legitimate and 'non-evil' uses of macros to me.

Earlier in this thread:

David said:
Not all macros are evil.

Example?[/QUOTE]

So I guess you answered your own question!
 
D

David Harmon

On Tue, 20 Apr 2004 03:56:40 -0700 in comp.lang.c++, "Paul Mensonides"
Despite your accusation, I haven't been beating around the bush.

Sure you are. After several back-and-forth you have not posted one
single #define to illustrate a single one of your claims. I go to the
files you list:
spirit/core/non_terminal/rule.hpp

Not a #define in sight except for
#if !defined(BOOST_SPIRIT_RULE_HPP)
#define BOOST_SPIRIT_RULE_HPP
spirit/core/non_terminal/impl/rule.ipp

Not a #define in sight except for
#if !defined(BOOST_SPIRIT_RULE_IPP)
#define BOOST_SPIRIT_RULE_IPP
spirit/dynamic/select.hpp

Not present in the version of Spirit I am using.
spirit/dynamic/impl/switch.ipp

Not present in the version of Spirit I am using.

I give up. It is like "Read the encyclopedia and you will see what I
mean."
I have been saying exactly what I mean: the preprocessor is used, for
example, to *generate* source code for the express purpose of minimizing
maintenance points and avoiding repetitive coding.

Total floating abstract nonsense. Source code is what comes out of your
keyboard; and it includes whatever preprocessor macros you write. If
you "generate" it, it wouldn't be *source*.

So, in trying to fathom what, if anything, you are talking about, I run
in to the following comment from Joel. Kinda sums it all up:


///////////////////////////////////////////////////////////////////////////
//
// BOOST_SPIRIT_CONTEXT_PARSE helper macro
//
// The original implementation uses a template class. However, we
// need to lessen the template instantiation depth to help inferior
// compilers that sometimes choke on deep template instantiations.
// The objective is to avoid code redundancy. A macro, in this case
// is an obvious solution. Sigh!
//
// WARNING: INTERNAL USE ONLY. NOT FOR PUBLIC CONSUMPTION.
//
///////////////////////////////////////////////////////////////////////////
 
D

David Harmon

On Tue, 20 Apr 2004 08:37:59 -0700 in comp.lang.c++, Julie
So I guess you answered your own question!

In a sense, yes. But the discussion is pretty pointless for me if I
have to supply all the answers. It doesn't get me any closer to
understanding what you or Christopher or Paul might have in mind.

C++ took a big step forward when it took a step away from the
preprocessor and toward compile-time metaprogramming integrated with the
language. We are not all the way there yet, and cannot yet abandon
macros completely in C++. Perhaps we should say that macros are a
"necessary evil."
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top