[comp.lang.c++] #defines....

slp@genrad.uucp (Steven L. Peters) (07/02/90)

Just out of curiousity...

With the C++ const, enum, and inline declarations, is it ever
necessary to use #define in a C++ program?  Stroustrup emphatically
says in _The C++ Programming Language_ not to use them if you don't
have to.  I'm wondering if you ever have to.  I can't think of a
single time where you would be forced to use a #define over const or
inline...

Sorry if this was discussed before.

				Stephen Peters

petrilli@walt.cc.utexas.edu (Chris Petrilli) (07/02/90)

In article <37786@genrad.UUCP> slp@genrad.genrad.COM (Steven L. Peters) writes:
>Just out of curiousity...
>
>With the C++ const, enum, and inline declarations, is it ever
>necessary to use #define in a C++ program?  Stroustrup emphatically
>says in _The C++ Programming Language_ not to use them if you don't
>have to.  I'm wondering if you ever have to.  I can't think of a
>single time where you would be forced to use a #define over const or
>inline...
>

The only time where you HAVE to use a #define (or at least, it is the best
way for clarity) is in conditionally compiled code.  For example:

#define DEBUG

#ifdef DEBUG
 ... (do something) ...
#endif

This would be more difficult under C++ convention of using constants, than
the preprocessor, since you don't care about type, just whether it is defined
or not.

Hope this clarifies it... if someone can thing of another time where you HAVE
to use the pre-processor, I'd like to know, I might be misusing/abusing 
C++.


+ Chris Petrilli                                    "Opinons represented here
| University of Texas at Austin                      do not necessarily
| INTERNET:  petrilli@vondrake.cc.utexas.edu         represent those of a sane
| SNAILMAIL: 429 Brady Lane, Austin, Texas, 78746    person.  Take them as
+ PHONE:     +1 512 327 0986                         simply that."

philip@pescadero.Stanford.EDU (Philip Machanick) (07/02/90)

In article <37786@genrad.UUCP>, slp@genrad.uucp (Steven L. Peters) writes:
> Just out of curiousity...
> 
> With the C++ const, enum, and inline declarations, is it ever
> necessary to use #define in a C++ program?  Stroustrup emphatically
> says in _The C++ Programming Language_ not to use them if you don't
> have to.  I'm wondering if you ever have to.  I can't think of a
> single time where you would be forced to use a #define over const or
> inline...
> 
Just a small example... errno, which contains an error number from
the most recent error (used in a number of common libraries) is defined
as an integer _expression_. It can for example be implemented as a
function call. Could the same effect be achieved with any of the new
constructs? I think not, because function calls and variable references
are syntactically different in C/C++ (unlike some other languages, where
a parameterless function looks like a variable reference).

Philip Machanick
philip@pescadero.stanford.edu

bright@Data-IO.COM (Walter Bright) (07/03/90)

In article <33133@ut-emx.UUCP> petrilli@walt.cc.utexas.edu (Chris Petrilli) writes:
<Hope this clarifies it... if someone can thing of another time where you HAVE
<to use the pre-processor, I'd like to know, I might be misusing/abusing 
<C++.


You need the preprocessor's help if you wish to insert __FILE__ and __LINE__s
in the right spots. Using inline functions doesn't work because the __FILE__
and __LINE__ will expand to where the inline function is defined, not where
it is used. For example:

    // Part of a package to track storage allocation
    #define malloc(n)	mem_malloc(n,__FILE__,__LINE__)
    #define new		((__file__ = __FILE__),(__line__ = __LINE__)),new

Another use that I find particularly useful:

    #if !(MSDOS || __OS2__)
    #define cdecl
    #define near
    #define far		/* make extended keywords go away	*/
    #endif

Or how about conditionally making static functions global:

    #ifdef DEBUG
    #define STATIC	/* make STATIC functions appear in .MAP file	*/
    #else
    #define STATIC static
    #endif

    STATIC int near function() { ... }

In other words, I think the preprocessor is here to stay.

Daniel_Gregory_Corbett@cup.portal.com (07/03/90)

Stephen Peters asks:
>Just out of curiousity...
>
>With the C++ const, enum, and inline declarations, is it ever
>necessary to use #define in a C++ program?  Stroustrup emphatically
>says in _The C++ Programming Language_ not to use them if you don't
>have to.  I'm wondering if you ever have to.  I can't think of a
>single time where you would be forced to use a #define over const or
>inline...

If you wish to use conditional compilation using #ifdef, and the like
then #defines are required.  const variables are not understood by cpp
and are therefore ignored.

Example:

#define DEBUG		/* This might be defined on the command line */
			/* using -DDEBUG */

#ifdef DEBUG
printf("Debug Statement i=%d\n", i);
#endifk


		- Daniel

lerman@stpstn.UUCP (Ken Lerman) (07/03/90)

In article <37786@genrad.UUCP> slp@genrad.genrad.COM (Steven L. Peters) writes:
[...]
>With the C++ const, enum, and inline declarations, is it ever
>necessary to use #define in a C++ program?  Stroustrup emphatically
>says in _The C++ Programming Language_ not to use them if you don't
>have to.  I'm wondering if you ever have to.  I can't think of a
>single time where you would be forced to use a #define over const or
>inline...
[...]
>				Stephen Peters


The following is (more or less) taken from a real application

#define GLOBAL(x) static char x[] = #x

GLOBAL(reader);
GLOBAL(writer);

Generates:

static char reader[] = "reader";
static char writer[] = "writer";

Without arguing the details, the point is that not every macro
generates executable code.  Functions cannot be used to create
declarations, and "const" does not provide the terseness (be it good,
bad, or indifferent) that macros provide.

Ken

steve@taumet.com (Stephen Clamage) (07/03/90)

In article <1990Jul2.164355.15327@Neon.Stanford.EDU> philip@pescadero.stanford.edu writes:
>Just a small example... errno, which contains an error number from
>the most recent error (used in a number of common libraries) is defined
>as an integer _expression_. It can for example be implemented as a
>function call....

But errno is not C++, it is C.  If you are required to use the C library
and headers, then you have lots of macros forced on you.  Realistically,
any real C++ program written today will use the C library and at least
some of the headers.  But C++ provides better mechanisms for all the macro
usages in C.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

ecsv38@castle.ed.ac.uk (S Manoharan) (07/03/90)

In article <37786@genrad.UUCP> slp@genrad.genrad.COM (Steven L. Peters) writes:
>have to.  I'm wondering if you ever have to.  I can't think of a
>single time where you would be forced to use a #define over const or
>inline...

1. To avoid multiple inclusion of header files.

2. Macros local to a function. As in:
#define _C(i,j)         ( *(C + nelements * i + j) )
where C is <some> ptr, and _C(i, j) defines element [i, j] of an array.
Note that an inline can't be local to a function.

Mano.

steve@taumet.com (Stephen Clamage) (07/05/90)

In article <5005@castle.ed.ac.uk> ecsv38@castle.ed.ac.uk (S Manoharan) writes:
>[when to use #define in C++]

>1. To avoid multiple inclusion of header files.

Thus creating a maintenance nightmare when one #define changes and
another doesn't.

>2. Macros local to a function. As in:
>#define _C(i,j)         ( *(C + nelements * i + j) )
>where C is <some> ptr, and _C(i, j) defines element [i, j] of an array.
>Note that an inline can't be local to a function.

But you can still do this with non-local inlines:

inline SomeType *_C( SomeType *C, int nelements, int i, int j)
{
    return C + nelements * i + j;
}

usage:
	... + * _C(C, nelements, i, j) + ...
	* _C(C, nelements, i, j)  = 0;

This generates exactly the same code as the macro (for any reasonable
compiler) and does not have the flaws of macros.  Macros have no
scope, and sometimes intrude where they are not wanted.  Your example
would have to start with
	#undef _C	/* in case previously defined */
and end with
	#undef _C	/* so it doesn't cause problems later */
But what if _C were defined as a global macro somewhere?  It is now lost.
If you don't use macros, they don't cause problems.  I am not speaking
of toy programs where one programmer holds the entire design in his head,
but of real-world multi-programmer projects.

A minor quibble:  Identifiers beginning with an underscore and an
uppercase letter are reserved.  But that is irrelevant to this discussion.

Second quibble:  2-dimensional arrays possibly could be used to avoid
writing this code at all (but not in all applications).
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

mckenney@sparkyfs.istc.sri.com (Paul Mckenney) (07/05/90)

In article <37786@genrad.UUCP> slp@genrad.genrad.COM (Steven L. Peters) writes:
>Just out of curiousity...

>With the C++ const, enum, and inline declarations, is it ever
>necessary to use #define in a C++ program?  Stroustrup emphatically
>says in _The C++ Programming Language_ not to use them if you don't
>have to.  I'm wondering if you ever have to.  I can't think of a
>single time where you would be forced to use a #define over const or
>inline...

Until templates are commonly implemented, I will use macros in their stead.

I also have used them in cases where I would use a nested function, if
such a beast were available in C++.  Macros have definite drawbacks,
but so do functions with tons of parameters.  The good news is that C++
classes can be used (abused?) to reduce the need for nested functions
(as compared to C).  The trick is to replace the top-level function
with a class, with the class's instance variables serving in place of
the function's local variables.  The code that was in the function and
in each local macro is then placed into a (possibly inlined) member
function.  There are still occasions where use of macros is cleaner,
particularly if macro concatenation and stringification facilities come
into play.  Perhaps nested classes will do even better.

						Thanx, Paul

roger@zuken.co.jp (Roger Meunier) (07/05/90)

One thing I wish you could do with inline functions is declare global
variables with a name passed as an argument.  For example, with #define
you can do the following:

typedef enum { Type1,Type2,Type3 } DataType;

class Data
{
	DataType	type;
	int		value;

	...
}

#define	MakeOrange(name,v)	Data	name = { Type1, v }
#define	MakeApple(name,v)	Data	name = { Type2, v }

MakeOrange(fruit1,100);
MakeApple(fruit2,200);

How could you do this with an inline function?  (If someone says,
"Use a constructor!" you've missed the point...)
--
Roger Meunier @ Zuken, Inc.  Yokohama, Japan	(roger@zuken.co.jp)

dan@dyndata.UUCP (Dan Everhart) (07/06/90)

In article <37786@genrad.UUCP> slp@genrad.uucp (Steven L. Peters) writes:
>   With the C++ const, enum, and inline declarations, is it ever
>   necessary to use #define in a C++ program? 

I don't know about *necessary* but I find it convenient to use the
following:  

#if defined(DEBUG)
#define pure	{ DebuggerTrap (); }
#else
#define	pure	= 0
#endif

class Xyz
   {
   // ...
   virtual f () pure;
   // ...
   } 

This quickly finds erroneous calls of pure virtual functions during
debugging, yet leaves no overhead in a production version.  It's also
highly readable.

In article <PCG.90Jul2225948@odin.cs.aber.ac.uk> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes:
>   arguable that 'this' (which should not exist, however) should be a
>   reference and not a pointer, but it's too late to change that.

A #define comes in handy here too:

#define self (*this)

I don't think you could do either of these tricks without using a #define.

jlol@ALTAR.EE.BYU.EDU (Jay Lawlor) (07/07/90)

>  With the C++ const, enum, and inline declarations, is it ever
>  necessary to use #define in a C++ program?  Stroustrup emphatically
>  says in _The C++ Programming Language_ not to use them if you don't
>  have to.  I'm wondering if you ever have to.  I can't think of a
>  single time where you would be forced to use a #define over const or
>  inline...

What about something like this?

#define QUIT(err) { do_some_cleanup_stuff(); return(err); }


With a macro, the return(err) returns from the function that invoked
QUIT, but with an inline function you can only "return" back to the
invoking function, right?

Not that you couldn't return some other way, but I just thought of
this when I was reading some code that used a similar #define.

Jay

pcg@cs.aber.ac.uk (Piercarlo Grandi) (07/07/90)

In article <9007062136.AA08003@ucbvax.Berkeley.EDU>
jlol@ALTAR.EE.BYU.EDU (Jay Lawlor) writes:

   >  With the C++ const, enum, and inline declarations, is it ever
   >  necessary to use #define in a C++ program?  Stroustrup emphatically
   >  says in _The C++ Programming Language_ not to use them if you don't
   >  have to.  I'm wondering if you ever have to.  I can't think of a
   >  single time where you would be forced to use a #define over const or
   >  inline...

   What about something like this?

   #define QUIT(err) { do_some_cleanup_stuff(); return(err); }


To settle the matter once and for all: macros are necessary to define
new syntax forms; this is often undesirable, where the new syntax is
merely a travesty of the old syntax, but is in some cases unavoidable.

For example there is no other way to achieve *control* abstraction,
because there is no such facility in the language for it. In the Lisp
and Scheme family of languages macros are used like this too, even if
they they have greater facilities to do control abstraction then the
lonely setjmp/longjmp of C/C++.

There are other cases where syntax abstraction is also justifiable; for
example you may want to implement a state machine as a switch inside a
for, but then you want to hide the implementation.

Outside syntax abstraction the use of the preprocessor should be
avoided.
--
Piercarlo "Peter" Grandi           | ARPA: pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk
Dept of CS, UCW Aberystwyth        | UUCP: ...!mcsun!ukc!aber-cs!pcg
Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk

steve@taumet.com (Stephen Clamage) (07/08/90)

In article <9007062136.AA08003@ucbvax.Berkeley.EDU> jlol@altar.ee.byu.edu writes:
>What about something like this?
>
>#define QUIT(err) { do_some_cleanup_stuff(); return(err); }

We've now seen a lot of stuff on this thread where someone shows a
macro which cannot be *precisely* duplicated with consts and inline
functions.

IMHO, the point is not to duplicate *precisely* what can be
done with macros, but to write clear, concise, efficient code --
code which can be understood and maintained easily.  So I must
ask whether these macro examples fit these criteria better than
other C++ language mechanisms.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

jef@well.sf.ca.us (Jef Poskanzer) (07/08/90)

In the referenced message, petrilli@walt.cc.utexas.edu (Chris Petrilli) wrote:
}The only time where you HAVE to use a #define (or at least, it is the best
}way for clarity) is in conditionally compiled code.  For example:
}
}#define DEBUG
}
}#ifdef DEBUG
} ... (do something) ...
}#endif

In many systems, the optimizers are smart enough to completely eliminate
code under a compile-time false if statement.  As in:

    const int debug = 0;

    if ( debug ) {
	(do something)
    }

Or whatever.  I have not checked whether this works in any C++ system,
but I have used it in numerous other systems, after checking the generated
machine instructions to be sure there was no run-time overhead.  One big
advantage of this over using the pre-processor is that the debugging code
gets syntax-checked, so you avoid bit rot.  One big disadvantage is that
it doesn't work on all systems, so it can't be considered portable.
---
Jef

  Jef Poskanzer  jef@well.sf.ca.us  {ucbvax, apple, hplabs}!well!jef
      A child of 5 could understand this!  Fetch me a child of 5.

roger@procase.UUCP (Roger H. Scott) (07/11/90)

In article <37786@genrad.UUCP> slp@genrad.genrad.COM (Steven L. Peters) writes:
>Just out of curiousity...
>
>With the C++ const, enum, and inline declarations, is it ever
>necessary to use #define in a C++ program?  Stroustrup emphatically
>says in _The C++ Programming Language_ not to use them if you don't
>have to.  I'm wondering if you ever have to.  I can't think of a
>single time where you would be forced to use a #define over const or
>inline...
>
Well, if C++ had types and functions as first-class-objects in the language
your statement might have a chance of being true, but since C++ doesn't your
statement doesn't.  As a simple example, how would you write achieve the
effect of a SWAP macro in C++?
#define SWAP(T,a,b) {T t = a; a = b; b = t;}

Until parameterized types come along (and they do the right thing), another
example is generation of declarations of parameterized types.

Another example is aliasing of identifier names in header files that you
can't change, e.g.:
read_only.h:
    class Foo {
	void dont_you_hate_this_lexical_style();
    };

clean_it_up.c:
    #include "read_only.h"
    #define differentLexicalStyle dont_you_hate_this_lexical_style

    ...
    p->differentLexicalStyle();

This list is not exhaustive.

dsa@dlogics.COM (David Angulo) (07/17/90)

> In article <37786@genrad.UUCP> slp@genrad.genrad.COM (Steven L. Peters) writes:
> >Just out of curiousity...
> >
> >With the C++ const, enum, and inline declarations, is it ever
> >necessary to use #define in a C++ program?  Stroustrup emphatically
> >says in _The C++ Programming Language_ not to use them if you don't
> >have to.  I'm wondering if you ever have to.  I can't think of a
> >single time where you would be forced to use a #define over const or
> >inline...
> >

Another example:  use it for compiler directives.  For example the
#include can be commented out like thus:

Module a:

	#ifndef a
	#define a
	...
	// rest of module a
	...
	#endif


module b:

	#ifndef a
	#include "a.h"
	#endif
	...
	// rest of module b


-- 
David S. Angulo                  (312) 266-3134
Datalogics                       Internet: dsa@dlogics.com
441 W. Huron                     UUCP: ..!uunet!dlogics!dsa
Chicago, Il. 60610               FAX: (312) 266-4473