[comp.lang.c] Just a minor new twist on free

funkstr@ucscb.ucsc.edu (Larry Hastings) (10/01/90)

Seeing as how people are just now discussing using heap memory after it's
been free()d, I thought I'd suggest this.  It's something that either I or
my boss came up with (I forget who).  And, yes, the whole purpose of its
existence is to have a "side-effect", but this one is IMHO worth it:

#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }

This takes care of two problems:
	1) If you access a pointer after smart_free()ing it, you are
	   dereferencing a null pointer, which gives you a lovely error message
	   (except on DOS, where I am doomed to stay).
	2) If you smart_free() something twice, nothing bad happens.  (The
	   pointer gets set to NULL the first time, and gets blocked by the
	   "if" the second time.)

Just remember that this is a macro when you call it, and don't do anything
funny like smart_free(*x++), and those heap manager problems will go away.

This joins an entire brace of "smart_" functions (smart_calloc(),
smart_open(), smart_close() and so on) which act "intelligently".
This mainly means they call the function they replace (smart_write() calls
write()) and check the return value -- if there's anything wrong, they abort.
--
larry hastings, the galactic funkster, funkstr@ucscb.ucsc.edu

I don't speak for Knowledge Dynamics or UC Santa Cruz, nor do they speak for me

The 4th law of Robotics (courtesy of Lore Shoberg):
"A robot must encourage proper dental hygiene, except where such encouragement
 would interfere with the 0th, 1st, 2nd, and 3rd laws."

cpcahil@virtech.uucp (Conor P. Cahill) (10/01/90)

In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes:
>
>#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }
>
>This takes care of two problems:
>	1) If you access a pointer after smart_free()ing it, you are
>	   dereferencing a null pointer, which gives you a lovely error message
>	   (except on DOS, where I am doomed to stay).

Only if you use the same pointer.  If the pointer had been copied somewhere
else (or a pointer within that area had been used) it still would point 
to the area that had been freed.

>	2) If you smart_free() something twice, nothing bad happens.  (The
>	   pointer gets set to NULL the first time, and gets blocked by the
>	   "if" the second time.)

I don't think you should do this.  If you are calling free twice with the
same pointer, something is wrong.  I would prefer an abort, so people could
track down the problem, not hide it.

A while back I put together a debugging library for malloc and it's
associated functions which was posted to comp.sources.unix back in may/june.
This library purposely trashes data pointed to by the free'd pointer to 
ensure that you aren't using a freed pointer (in addition to lots
of other checks, like overrunning the amount of malloc data that you 
asked for).

If you are working with malloc'd data, you might want to get a copy of 
the library.  It makes solving most malloc problem easy.

-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

pds@lemming.webo.dg.com (Paul D. Smith) (10/01/90)

In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes:


[] #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }


It should be pointed out that in ANSI C free(NULL) is defined, and is
legal (any conforming implementation of free() must ignore being
passed a NULL pointer).

So, you could save yourself some execution time (if you have an ANSI
compiler) by writing:

#define smart_free(x) { free(x); x = NULL; }

(you may also want to peruse the seperate thread in this newsgroup on
multi-statement macros and `while(0)' loops, etc.)
--

                                                                paul
-----
 ------------------------------------------------------------------
| Paul D. Smith                          | pds@lemming.webo.dg.com |
| Data General Corp.                     |                         |
| Network Services Development           |   "Pretty Damn S..."    |
| Open Network Applications Department   |                         |
 ------------------------------------------------------------------

rtidd@ccels3 (Randy Tidd) (10/01/90)

In article <1990Oct01.020420.3401@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> 
> [ ... ]
>
>A while back I put together a debugging library for malloc and it's
>associated functions which was posted to comp.sources.unix back in may/june.
>This library purposely trashes data pointed to by the free'd pointer to 
>ensure that you aren't using a freed pointer (in addition to lots
>of other checks, like overrunning the amount of malloc data that you 
>asked for).
>
>If you are working with malloc'd data, you might want to get a copy of 
>the library.  It makes solving most malloc problem easy.

I checked comp.sources.unix on my news server and it doesn't have ANY
messages in it, much less the ones from may/june. If anyone has a copy
of the routines Conor talks about here, can they mail them to me?  I
tried mailing him directly but it bounced.

Thanks in advance!

Randy Tidd
rtidd@mwunix.mitre.org

"It's easier to get forgiveness than permission."

roger@everexn.com (Roger House) (10/02/90)

In <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes:

>#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }

>This takes care of two problems:
>	1) If you access a pointer after smart_free()ing it, you are
>	   dereferencing a null pointer, which gives you a lovely error message
>	   (except on DOS, where I am doomed to stay).
>	2) If you smart_free() something twice, nothing bad happens.  (The
>	   pointer gets set to NULL the first time, and gets blocked by the
>	   "if" the second time.)

The ANSI C standard states that when the argument to free is a null pointer,
nothing happens.  So if your free function is ANSI, there is no need to check
for NULL to avoid calling free.

As for setting the pointer to NULL after freeing, I have done this for quite
some time, and it has quickly caught several bugs that could have turned into
nightmares.  However, I define a function, myfree, so I don't need to worry
about side-effects (the argument to the function is void **).  Another ad-
vantage of having a function is that then all heap operations are funneled
through a couple of my functions (mymalloc, myfree, myrealloc, etc.)  This
is very useful if you decide you want to do things like keep track of the
maximum amount of heap memory in use at a given time, etc.

Also, on occasion I use test versions of mymalloc and myfree which do things
like this:  my malloc saves all its return values in a table, and when myfree
is called it checks that the address of the space to be freed is in the table,
and then removes it from the table.  This mechanism has also saved me from
a few nasty heap bugs.

							Roger House

6sigma2@polari.UUCP (Brian Matthews) (10/02/90)

In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes:
|#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }

A run-time solution to a compile-time problem.  Blecch.
-- 
Brian L. Matthews	blm@6sceng.UUCP

cpcahil@virtech.uucp (Conor P. Cahill) (10/02/90)

In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>It should be pointed out that in ANSI C free(NULL) is defined, and is
>legal (any conforming implementation of free() must ignore being
>passed a NULL pointer).

While this is a true statement, I would never recommend that one take advantage
of this feature.  If you know the variable is NULL don't pass it to free.

The performance cost of the following statement:

		if( ptr != NULL )
			free(ptr);

as opposed to:

		free(ptr);

will be unmeasurable in most, if not all, circumstances.  In addition, by
adding the if() you get code that is portable across all implementations.

Anyway, this is really a moot point because you should never be calling
free() unless you KNOW WHAT IS IN THE PTR that you will be passing to it.
If you don't, then something is wrong with your code.

-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

kdq@demott.COM (Kevin D. Quitt) (10/02/90)

In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes:
>
>
>[] #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }
>
>
>It should be pointed out that in ANSI C free(NULL) is defined, and is
>legal (any conforming implementation of free() must ignore being
>passed a NULL pointer).
>
>So, you could save yourself some execution time (if you have an ANSI
>compiler) by writing:
>
>#define smart_free(x) { free(x); x = NULL; }
>

    Actually, execution time will be saved by the original definition,
since it avoids the call/return overhead in invoking free when the
pointer is null.  This was discussed a month or so ago, and timings were
published. 

-- 
 _
Kevin D. Quitt         demott!kdq   kdq@demott.com
DeMott Electronics Co. 14707 Keswick St.   Van Nuys, CA 91405-1266
VOICE (818) 988-4975   FAX (818) 997-1190  MODEM (818) 997-4496 PEP last

                96.37% of all statistics are made up.

pds@lemming.webo.dg.com (Paul D. Smith) (10/03/90)

In article <1990Oct02.132313.6659@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes:

[] In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
[] >It should be pointed out that in ANSI C free(NULL) is defined, and is
[] >legal (any conforming implementation of free() must ignore being
[] >passed a NULL pointer).
[]
[] While this is a true statement, I would never recommend that one
[] take advantage of this feature.  If you know the variable is NULL
[] don't pass it to free.

Obviously if you know it's NULL, why would you call free()?  This is a
no-brainer.  The problem arises when you *don't* know if it's NULL or
not -- I thought that's why we have the if() test!

[] The performance cost of the following statement:
[]
[]                 if( ptr != NULL )
[]                         free(ptr);
[]
[] as opposed to:
[]
[]                 free(ptr);
[]
[] will be unmeasurable in most, if not all, circumstances.

Well, IMHO, this is just silliness.  What are you saying, that no one
should use ANSI extensions if they have an ANSI compiler just because
they didn't *used* to be legal?

While your simple case might indeed not be much of a performance hit,
what about something like:

    #define ARRAY_LEN   10000
    char *array[ARRAY_LEN], *ap;
    int i;

    for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
    {
        if (ap != NULL)
            free(ap)
    }

Now, *this* is a significant performance hit, if you consider an extra
10000 comparisons.  Before you retort about using memset() or bzero(),
please read the FAQ on NULL pointers ... and no, I wouldn't do it this
way either, but it is not hard to see where extraneous tests *can*
cause some loss of performance, not to mention loss of programmer time
typing them in!

Besides, I think it is correct behavior for free() to handle a NULL
pointer, and it should have done all along.

[] Anyway, this is really a moot point because you should never be calling
[] free() unless you KNOW WHAT IS IN THE PTR that you will be passing to it.
[] If you don't, then something is wrong with your code.

So what are you saying, that in the above case I should have a bitmap
with ARRAY_LEN bits which tells me which of the pointers in `array'
actually have values and which are NULL?  More silliness.

[] In addition, by adding the if() you get code that is portable
[] across all implementations.

Ok, now *this* is a valid concern.  So, rewrite the macro in question:

#ifdef __STDC__
#define smart_free(_p)  { free(_p); (_p)=NULL; }
#else
#define smart_free(_p)  { if ((_p)!=NULL) { free(_p); (_p)=NULL; } }
#endif

--

                                                                paul
-----
 ------------------------------------------------------------------
| Paul D. Smith                          | pds@lemming.webo.dg.com |
| Data General Corp.                     |                         |
| Network Services Development           |   "Pretty Damn S..."    |
| Open Network Applications Department   |                         |
 ------------------------------------------------------------------

jeenglis@alcor.usc.edu (Joe English Muffin) (10/04/90)

pds@lemming.webo.dg.com (Paul D. Smith) writes:

>Well, IMHO, this is just silliness.  What are you saying, that no one
>should use ANSI extensions if they have an ANSI compiler just because
>they didn't *used* to be legal?

That's a valid concern.  There are a LOT of
systems out there that don't have an ANSI
C compiler, and there will be for a long long
time to come.

...

>    #define ARRAY_LEN   10000
>    char *array[ARRAY_LEN], *ap;
>    int i;
>    for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
>    {
>        if (ap != NULL)
>            free(ap)
>    }

>Now, *this* is a significant performance hit, if you consider an extra
>10000 comparisons. 

Doing the test will most likely INCREASE performance:
a test is usually cheaper than a function call, and
free() is not a trivial function.  Ever profiled a
program that made heavy use of malloc() & free()?
They eat up a lot of cycles.  (Unless the RTL is
implemented really well; personally, I've never seen a
fast implementation of malloc() & free().)


--Joe English

  jeenglis@alcor.usc.edu

cpcahil@virtech.uucp (Conor P. Cahill) (10/04/90)

It appears you took my comments as a personal attack, which they were not
meant to be.  However, you raised some points that I will respond to...

In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>In article <1990Oct02.132313.6659@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes:
>[] While this is a true statement, I would never recommend that one
>[] take advantage of this feature.  If you know the variable is NULL
>[] don't pass it to free.
>
>Obviously if you know it's NULL, why would you call free()?  This is a
>no-brainer.  The problem arises when you *don't* know if it's NULL or
>not -- I thought that's why we have the if() test!

You say this and then you make an argument for calling free with a NULL anyway?

>[] The performance cost of using if( ptr!= NULL) free(ptr)  as opposed to
>[] free(ptr) (with no if) will be unmeasurable in most if not all
>[] circumstances.
>
>Well, IMHO, this is just silliness.  What are you saying, that no one
>should use ANSI extensions if they have an ANSI compiler just because
>they didn't *used* to be legal?

I am saying that the if(ptr!=NULL) is almost a "free" operation (using only
one or two instructions on many machines).  If you use it, the code will
work correctly on ANSI and pre-ANSI, and the peformance difference will 
not be measurable.  (The key word is measurable).

>While your simple case might indeed not be much of a performance hit,
>what about something like:
>
>    #define ARRAY_LEN   10000
>    char *array[ARRAY_LEN], *ap;
>    int i;
>
>    for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
>    {
>        if (ap != NULL)
>            free(ap)
>    }
>
>Now, *this* is a significant performance hit, if you consider an extra

No it is not.  Actually, if array has greater than a small percentage 
of NULL pointers, the savings of the function call by the if test will
be substantial.   Rember, comparisons (especially comparisons against 
zero) are a very cheap operation.  Function calls are not.

>10000 comparisons.  Before you retort about using memset() or bzero(),
>please read the FAQ on NULL pointers ... and no, I wouldn't do it this

I didn't meantion bzero or memset anywhere so I'm not sure why the
reference is here.

>way either, but it is not hard to see where extraneous tests *can*
>cause some loss of performance, not to mention loss of programmer time
>typing them in!

Before you say it *can*, try it and you will find that you can't measure
the difference in a *real* program.

>Besides, I think it is correct behavior for free() to handle a NULL
>pointer, and it should have done all along.

I don't, but that is just personal opinion and both of us can have our
own. 

>[] Anyway, this is really a moot point because you should never be calling
>[] free() unless you KNOW WHAT IS IN THE PTR that you will be passing to it.
>[] If you don't, then something is wrong with your code.
>
>So what are you saying, that in the above case I should have a bitmap
>with ARRAY_LEN bits which tells me which of the pointers in `array'
>actually have values and which are NULL?  More silliness.

No.  if you assigned null to all the pointers originally, then you only need
to call free if the pointer is not NULL.

>[] In addition, by adding the if() you get code that is portable
>[] across all implementations.
>
>Ok, now *this* is a valid concern.  So, rewrite the macro in question:
>
>#ifdef __STDC__
>#define smart_free(_p)  { free(_p); (_p)=NULL; }
>#else
>#define smart_free(_p)  { if ((_p)!=NULL) { free(_p); (_p)=NULL; } }
>#endif

While this is a valid construct, I still maintain that you won't be
able to measure the difference in execution time and therefore make
your code more complex needlessly.

-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) (10/05/90)

In article <7365@darkstar.ucsc.edu>, funkstr@ucscb.ucsc.edu (Larry Hastings) writes:
> [ ...]
> 
> #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } }

<<sigh>>  How quickly they forget...

From the thread on how to do if's in a macro:

	#define smart_free(x)  ( ((x) !=NULL) && (free(x),0) )

From the thread on the meaning of NULL:

	#define smart_free(x)  ( ((x) != 0) && (free(x),0) )
which collapses to
	#define smart_free(x)  ( (x) && (free(x),0) )

Now, somebody please remind ME:  Is "(free(x),0)" what the netsters came
up with as the best wat to do a void function, or should it be something
else?

BTW, I'm not taking sides on whether one _should_ test the value of x
before calling free(x).  My point is just that I hate to see all the
other good comments about macros and NULL disappear into oblivion.


The above is my own opinion and not attributable to any other person or
organization.                        email: browns@iccgcc.decnet.ab.com
Stan Brown, Oak Road Systems, Cleveland, Ohio, U.S.A.    (216) 371-0043

gegu@bii.UUCP (Gerhard Gucher) (10/05/90)

> In article <PDS.90Oct3103126@lemming.webo.dg.com>, pds@lemming.webo.dg.com (Paul D. Smith) writes:

>     #define ARRAY_LEN   10000
>     char *array[ARRAY_LEN], *ap;
>     int i;
> 
>     for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
>     {
>         if (ap != NULL)
>             free(ap)
>     }
> 
> Now, *this* is a significant performance hit, if you consider an extra
> 10000 comparisons.  Before you retort about using memset() or bzero(),
> please read the FAQ on NULL pointers ... and no, I wouldn't do it this
> way either, but it is not hard to see where extraneous tests *can*
> cause some loss of performance, not to mention loss of programmer time
> typing them in!
> 
> Besides, I think it is correct behavior for free() to handle a NULL
> pointer, and it should have done all along.
> 
> 
>> In addition, by adding the if() you get code that is portable
>> across all implementations.
> 
> Ok, now *this* is a valid concern.  So, rewrite the macro in question:


Let's think a bit about "this significant performance hit".  

case 1:		ap == NULL  for > 90% of all cases

    WE GAIN by saving more than 9000 dummy function calls !! 

case 2:		ap == NULL  for 10% ... 90% of all cases

    WE GAIN by trading function calls for if's ( if's are MUCH cheaper )

case 3:		ap == NULL  for < 10% of all cases 

    WE LOOSE VERY LITTLE because we can't measure >9000 if's compared
                         to those >9000 fully executed frees. 

Now again, how was that with that *significant* performance hit ??

And as we all agree (I hope), the gain of portability to non ANSI
systems is well worth it anyways. (Keep in mind, most in use systems
don't carry ANSI yet ( Mess - DOS doesn't count as a system (:-) ).

--
  Disclaimer: My employer has nothing to to with this.
--

+------------------------------------------------------------------+
| Gerry Gucher    uunet!bii!gegu       gegu@bii.bruker.com	   |
| Bruker Instruments Inc. Manning Park Billerica MA 01821          | 
+------------------------------------------------------------------+

rtm@christmas.UUCP (Richard Minner) (10/05/90)

I personally like all `destroy_thing()' functions to quietly
accept a non-existent (NULL) `thing'.  (After all, what I want
is for the thing to be gone, and if it's already not there,
that's fine with me. :-)

I find all the `if (ptr)' tests cluttersome (not a real word).
If the thing really should not be null, I'll do an assert(thing)
before destroying it.

One particular usage this model simplifies is the multiple create, e.g:

	thing1 = create_thing();
	thing2 = create_thing();
	...
	thingN = create_thing();
	if (!thing1 || !thing2 || ... || !thingN)
	{
		destroy_thing(thing1);
		...
		destroy_thing(thingN);
		<fail>
	}

which to me reads nicely as: "try to get things, if didn't get
them all, get rid of any you got."

As a final bit, I second the recommendation of using your own
`shell' functions around the standard malloc family, rather than
macros; it's more flexible (as noted by ??, sorry) and the overhead
of the `extra' call is (almost always) insignificant compared to the
work the library functions will be doing.

-- 
Richard Minner  || {uunet,sun,well}!island!rtm     (916) 736-1323 ||
                || Island Graphics Corporation     Sacramento, CA ||

seanf@sco.COM (Sean Fagan) (10/05/90)

In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>While your simple case might indeed not be much of a performance hit,
>what about something like:
>
>    #define ARRAY_LEN   10000
>    char *array[ARRAY_LEN], *ap;
>    int i;
>    for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
>    { if (ap != NULL) free(ap); }
>
>Now, *this* is a significant performance hit, if you consider an extra
>10000 comparisons.  

And now an ANSI compliant library must have free() check for a NULL
parameter, which means that, instead of 10000 tests, you are now doing 20000
tests.  Yep.  Just love those performance increases, don't you?

Incidently, in reformating the included text to make news happy, I very
nicely got rid of the syntax error (a missing semicolon).  Tsk tsk tsk 8-).

-- 
-----------------+
Sean Eric Fagan  | "Never knock on Death's door:  ring the bell and 
seanf@sco.COM    |   run away!  Death really hates that!"
uunet!sco!seanf  |     -- Dr. Mike Stratford (Matt Frewer, "Doctor, Doctor")
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

kdq@demott.COM (Kevin D. Quitt) (10/07/90)

In article <1990Oct04.110928.16788@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes:
>It appears you took my comments as a personal attack, which they were not
>meant to be.  However, you raised some points that I will respond to...
>
>In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>>While your simple case might indeed not be much of a performance hit,
>>what about something like:
>>
>>    #define ARRAY_LEN   10000
>>    char *array[ARRAY_LEN], *ap;
>>    int i;
>>
>>    for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
>>    {
>>        if (ap != NULL)
>>            free(ap)
>>    }
>>
>>Now, *this* is a significant performance hit, if you consider an extra
>
>No it is not.  Actually, if array has greater than a small percentage 
>of NULL pointers, the savings of the function call by the if test will
>be substantial.   Rember, comparisons (especially comparisons against 
>zero) are a very cheap operation.  Function calls are not.
>
>>10000 comparisons.  Before you retort about using memset() or bzero(),
>>please read the FAQ on NULL pointers ... and no, I wouldn't do it this

    On the three systems I'm using, this is faster than the call without
the if, not slower! Testing for 0 is *much* faster than the overhead of
a function call - which function starts with a test for zero.  So if I
test first, I pay the penalty for comparing against zero.  If it's zero
I have a major win; if it's not, I pay a few percent in performance
penalty.  Have you folks actually tried timing your examples instead
of just using gedanken experiments?


-- 
 _
Kevin D. Quitt         demott!kdq   kdq@demott.com
DeMott Electronics Co. 14707 Keswick St.   Van Nuys, CA 91405-1266
VOICE (818) 988-4975   FAX (818) 997-1190  MODEM (818) 997-4496 PEP last

                96.37% of all statistics are made up.

rtm@christmas.UUCP (Richard Minner) (10/08/90)

In article <8026@scolex.sco.COM> seanf (Sean Fagan) writes:
>In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>>Now, *this* is a significant performance hit, if you consider an extra
>>10000 comparisons.  
>And now an ANSI compliant library must have free() check for a NULL
>parameter, which means that, instead of 10000 tests, you are now doing 20000
>tests.  Yep.  Just love those performance increases, don't you?

Sorry, I just can't stand it anymore.  This is about the fourth or fifth
posting talking about `performance' in this way.  Isn't someone going
to comment?  (I guess I am.)

Quick Quiz:  Is saving an hour of CPU time significant?
		a) Yes  b) No  c) Not enough information

If you answered a) or b), go back and re-read the chapter on performance
and efficiency.  If you don't consider the whole job, you can't talk
about performance in any meaningful way.  E.g. go to Bank of America
and tell them how you can save them an hour of CPU time each year. 
I don't think they'll be very impressed.  Tell me how I can cut my
image conversion from 80 minutes to 20 and you'll have my full attention.
Tell me how I can cut my nightly batch job from 80 minutes to 20 and
I might be curious, but won't really care.

Please stop talking about `10000 comparisons' as if it meant something.
I'm sorry, but you might as well make it 10 million; performance is
relative.  The time for one more `if' is not signifcant compared to
the rest of the work free() has to do.  (If you have an implementation
of free() for which one test *is* significant, I'd like to know about
it.  By the way, I don't consider 1% very significant.)

As someone recently mentioned, the big performance gains are from
good algorithms and design; shaving instructions is the last concern
and only when you have good reason to believe you are doing so in
a very critical portion of the code.  For example, if you have to
do 10000 allocations/frees where performance matters, you're probably
going to want your own memory manager tuned to your needs, rather than
using malloc/free which are quite general and often not the most efficient
for a particular task.

The ANSI behavior for free() is a good thing.  I don't want to read
any more complaints about it ;-)


-- 
Richard Minner  || {uunet,sun,well}!island!rtm     (916) 736-1323 ||
                || Island Graphics Corporation     Sacramento, CA ||

msb@sq.sq.com (Mark Brader) (10/09/90)

> While your simple case might indeed not be much of a performance hit,
> what about something like:
>     #define ARRAY_LEN   10000
>     char *array[ARRAY_LEN], **ap;
>     int i;
>     for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap)
>     {
>         if (*ap != NULL)
>             free(*ap);
>     }

/* Syntax and type errors corrected - msb */

That's probably still not a significant performance hit.  On the machine
I'm typing this on, it appears to cost somewhat under 0.1 second of CPU.
Even on a slower machine, a real-life program would be *doing* something
with those ten thousand malloc()ed objects, and the cost of ten thousand
compares and branches would probably be negligible in comparison.

Or to put it another way: if you need to execute "if (p) free (p);" so
many times that the "if (p)" tests contribute significantly to the cost
of the program, then you probably need to reorganize the program.

-- 
Mark Brader		"The last 10% of the performance sought contributes
Toronto			 one-third of the cost and two-thirds of the problems."
utzoo!sq!msb, msb@sq.com				-- Norm Augustine

This article is in the public domain.

dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) (10/10/90)

In article <11@christmas.UUCP> rtm@island.uu.net (Richard Minner) writes:
>In article <8026@scolex.sco.COM> seanf (Sean Fagan) writes:
>>And now an ANSI compliant library must have free() check for a NULL
>>parameter, which means that, instead of 10000 tests, you are now doing 20000
>>tests.  Yep.  Just love those performance increases, don't you?
>
>
>The ANSI behavior for free() is a good thing.  I don't want to read
>any more complaints about it ;-)
>

Perfromance isn't really the issue, it's a shame that's what everyone 
keeps bringing up. The performance hit of testing if (ptr == NULL) is 
insignificant whether the test is made before the call to free or within 
free itself.

I'd prefer free not check for NULL pointers because I'd rather have 
my sloppy (and probably incorrect) programming caught by a core dump
than slipping by untouched. I never check for NULL pointers in library
routines that I write unless there is a useful action that should be taken
when that pointer is NULL.



--
Dave Eisen                      	    Home: (415) 323-9757
dkeisen@Gang-of-Four.Stanford.EDU           Office: (415) 967-5644
1447 N. Shoreline Blvd.
Mountain View, CA 94043

bilbo@bisco.kodak.COM (Charles Tryon) (10/11/90)

In <1990Oct10.155448.1465@Neon.Stanford.EDU>, dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes:
> In article <11@christmas.UUCP> rtm@island.uu.net (Richard Minner) writes:
> >In article <8026@scolex.sco.COM> seanf (Sean Fagan) writes:
> >>And now an ANSI compliant library must have free() check for a NULL
> >>parameter, which means that, instead of 10000 tests, you are now doing 20000
> >>tests.  Yep.  Just love those performance increases, don't you?
> >
> >The ANSI behavior for free() is a good thing.  I don't want to read
> >any more complaints about it ;-)
> 
  ....
> I'd prefer free not check for NULL pointers because I'd rather have 
> my sloppy (and probably incorrect) programming caught by a core dump
> than slipping by untouched. I never check for NULL pointers in library
> routines that I write unless there is a useful action that should be taken
> when that pointer is NULL.

  Wouldn't it be more graceful to check for invalid data (such as, but not
  limited to NULL pointers), and on an error condition print a MESSAGE and
  exit gracefully (perhaps with a core dump to allow a debugger to give you
  trace-back information).  Assuming that a program will crash is a very
  dangerous thing (not to mention, not very friendly), since it might choose
  instead to just hose up memory and continue on as if nothing had happened.
  Remember that YOU probably won't be the only person using your software,
  and other people strongly frown upon unexplained crashes.

> Dave Eisen                      	    Home: (415) 323-9757

--
Chuck Tryon
    (PLEASE use this address, as Kodak foobars one in header!)
    <bilbo@bisco.kodak.com>
    USmail: 46 Post Ave.;Roch. NY 14619                       B. Baggins
    <<...include standard disclamer...>>                      At Your Service

     "Then again, squirrels could be stupid."   (D. Mocsny)

steve@taumet.com (Stephen Clamage) (10/11/90)

dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes:

>I'd prefer free not check for NULL pointers because I'd rather have 
>my sloppy (and probably incorrect) programming caught by a core dump
>than slipping by untouched. I never check for NULL pointers in library
>routines that I write unless there is a useful action that should be taken
>when that pointer is NULL.

The problem with this approach is that you can't depend on an immediate
core dump just because the current pointer is incorrectly null.  The
core dump may occur at any arbitrary later time due to following garbage
pointers -- or the program may not abort, but loop forever or do something
bizarre.  In particular, the problem may occur only after doing some
irreversible bad thing -- like deleting all the files from your disk, or
launching a missile with a nuclear warhead.  It is inconvenient to have to
rebuild your disk (or San Francisco) before trying to track down the
program bug.

IMHO, it is best to program defensively and catch errors as soon as possible.
A library function should return an explicit or implicit error code --
or do nothing -- rather than try to use invalid data.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

blodgett@apollo.HP.COM (Bruce Blodgett) (10/12/90)

If you are trying to compile code which may call free() with a NULL
argument, and use an implementation of free() that does not handle NULL
gracefully, try adding one of the following to <stdlib.h>:

#define free(x) ( (x) ? free(x) : ( (void)0 ) )
  or
#define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); }

The former has the side-effect of evaluating the argument to free()
twice.  The latter is a statement rather than an expression of type
void, and therefore wouldn't work if someone tried to embed a call to
free() in an expression (there are not many uses for subexpressions of
type void).
Bruce Blodgett
blodgett@apollo.hp.com
(508) 256-0176 x4037

cpcahil@virtech.uucp (Conor P. Cahill) (10/12/90)

I know I hate people pushing thier own software, but I thought just one 
more time....

In article <9010111342.AA18267@bisco.kodak.COM> nobody@Kodak.COM writes:
>  Wouldn't it be more graceful to check for invalid data (such as, but not
>  limited to NULL pointers), and on an error condition print a MESSAGE and
>  exit gracefully (perhaps with a core dump to allow a debugger to give you
>  trace-back information). 

This is exactly how the debuggin malloc library that was posted to c.s.u
back in may works.  You link it with your program (no changes are necessary
to your program, you don't even have to re-compile it - just relink it)
and you have a full set of checks on the typical problems that are 
prevalent in malloc usage.

Try it, you'll like it.
-- 
Conor P. Cahill            (703)430-9247        Virtual Technologies, Inc.,
uunet!virtech!cpcahil                           46030 Manekin Plaza, Suite 160
                                                Sterling, VA 22170 

gdtltr@freezer.it.udel.edu (Gary Duzan) (10/12/90)

In article <4d5780ad.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes:
=>
=>If you are trying to compile code which may call free() with a NULL
=>argument, and use an implementation of free() that does not handle NULL
=>gracefully, try adding one of the following to <stdlib.h>:
=>
=>#define free(x) ( (x) ? free(x) : ( (void)0 ) )
=>  or
=>#define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); }
=>
=>The former has the side-effect of evaluating the argument to free()
=>twice.  The latter is a statement rather than an expression of type
=>void, and therefore wouldn't work if someone tried to embed a call to
=>free() in an expression (there are not many uses for subexpressions of
=>type void).

   Both will also have the property of recursively expanding free() forever.
Better to call it something else. Your cpp will thank you for it.

                                        Gary Duzan
                                        Time  Lord
                                    Third Regeneration



-- 
                          gdtltr@freezer.it.udel.edu
   _o_                    --------------------------                      _o_
 [|o o|]        An isolated computer is a terribly lonely thing.        [|o o|]
  |_O_|         "Don't listen to me; I never do." -- Doctor Who          |_O_|

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/12/90)

In article <4d5780ad.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes:
> If you are trying to compile code which may call free() with a NULL
> argument, and use an implementation of free() that does not handle NULL
> gracefully, try adding one of the following to <stdlib.h>:
> #define free(x) ( (x) ? free(x) : ( (void)0 ) )
> #define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); }

Much better:

  #define free(x) ( ( __frx = x ) , ( __frx ? __frol(__frx) : (void) 0 ) )
  extern void *__frx;
  extern void (*__frol)();

In the library source, undef free, define __frx, and define __frol
initialized to &free.

---Dan

rbutterworth@watmath.waterloo.edu (Ray Butterworth) (10/12/90)

In article <10066:Oct1212:30:5790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>Much better:
>  #define free(x) ( ( __frx = x ) , ( __frx ? __frol(__frx) : (void) 0 ) )
>  extern void *__frx;
>  extern void (*__frol)();

Which will blow up if an interrupt occurs and changes the value of __frx
between the assignment and the test, or the test and the __frol call.
(Considering the environment under which C was developed,
 it's amazing how non-reentrant so much of the library is.)

In article <4d5780ad.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes:
> #define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); }

You should call it FREE, but even then something like
"if (test) FREE(thing); else something_else();"
would give a syntax error.

Macros like that should be written as
#define NAME(arg) do { auto thing=arg; ... ; } while(0)
They still can't be used as expressions,
but at least they can be used in "if" statements.

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/14/90)

In article <1990Oct12.162928.21807@watmath.waterloo.edu> rbutterworth@watmath.waterloo.edu (Ray Butterworth) writes:
> In article <10066:Oct1212:30:5790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >Much better:
> >  #define free(x) ( ( __frx = x ) , ( __frx ? __frol(__frx) : (void) 0 ) )
> >  extern void *__frx;
> >  extern void (*__frol)();
> Which will blow up if an interrupt occurs and changes the value of __frx
> between the assignment and the test, or the test and the __frol call.

So what? The system's free() isn't reentrant either. Now do you see
something incorrect about my implementation, or are you just posting so
you can complain about how difficult it is to use threads in C? If the
latter, try proposing some solutions in alt.lang.cfutures.

---Dan

pds@lemming.webo.dg.com (Paul D. Smith) (10/15/90)

[] ... try adding one of the following to <stdlib.h>

Oh no! Not that!  *Never* *ever* *change* the standard libraries which
ship with your compiler! (unless they don't work ;-)  Put it in some
local header file please, I don't want to change my nice, working,
ASNI-compliant header files in order to compile your program...

-- This has been a public service announcement from your local
-- ANSI-promoter; any flames by e-mail please!
--

                                                                paul
-----
 ------------------------------------------------------------------
| Paul D. Smith                          | pds@lemming.webo.dg.com |
| Data General Corp.                     |                         |
| Network Services Development           |   "Pretty Damn S..."    |
| Open Network Applications Department   |                         |
 ------------------------------------------------------------------

jtc@van-bc.wimsey.bc.ca (J.T. Conklin) (10/16/90)

In article <PDS.90Oct15104036@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>Oh no! Not that!  *Never* *ever* *change* the standard libraries which
>ship with your compiler! (unless they don't work ;-)  Put it in some
>local header file please, I don't want to change my nice, working,
>ANSI-compliant header files in order to compile your program...

At UniFax, we ANSIfy the development environment on all of our
development machines.  Header files get protoized and missing
functions get added to the C library.

It is hoped that the vendors will finally get the idea, but until then
we feel that maintaining these development environments is worth the
effort.

	--jtc

-- 
J.T. Conklin	UniFax Communications Inc.
		...!{uunet,ubc-cs}!van-bc!jtc, jtc@wimsey.bc.ca

pds@lemming.webo.dg.com (Paul D. Smith) (10/17/90)

[] In article <PDS.90Oct15104036@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
[] >Oh no! Not that!  *Never* *ever* *change* the standard libraries which
[] >ship with your compiler! (unless they don't work ;-)  Put it in some
[] >local header file please, I don't want to change my nice, working,
[] >ANSI-compliant header files in order to compile your program...

[] At UniFax, we ANSIfy the development environment on all of our
[] development machines.  Header files get protoized and missing
[] functions get added to the C library.

I'd say all this falls under the "unless they don't work" category! :-)  
Even so, as has already been mentioned, there are probably better ways
of doing it than changing the standard includes.

I have more than once been bitten by adding/changing things in the /
and /usr directories which were shipped with the product, and having
many things not work (I once changed the owner of /usr/bin/login to
"bin" instead of root; now just *try* to login as anything except
root!  And it took a whole day to discover the problem.)

What do you do if you need to compile a program which relies on the
old headers?
--

                                                                paul
-----
 ------------------------------------------------------------------
| Paul D. Smith                          | pds@lemming.webo.dg.com |
| Data General Corp.                     |                         |
| Network Services Development           |   "Pretty Damn S..."    |
| Open Network Applications Department   |                         |
 ------------------------------------------------------------------

jtc@van-bc.wimsey.bc.ca (J.T. Conklin) (10/18/90)

[Followup to comp.lang.c]

In article <PDS.90Oct17102409@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>[] At UniFax, we ANSIfy the development environment on all of our
>[] development machines.  Header files get protoized and missing
>[] functions get added to the C library.
>
>I'd say all this falls under the "unless they don't work" category! :-)  
>Even so, as has already been mentioned, there are probably better ways
>of doing it than changing the standard includes.

If it can me done well, it is a definite bonus.  The source code of
your project or product can remain relatively free of #ifdef's.  I
have found that this has significantly improved maintainability.

>I have more than once been bitten by adding/changing things in the /
>and /usr directories which were shipped with the product, and having
>many things not work (I once changed the owner of /usr/bin/login to
>"bin" instead of root; now just *try* to login as anything except
>root!  And it took a whole day to discover the problem.)

>What do you do if you need to compile a program which relies on the
>old headers?

It is possible to carefully edit the standard header files to work
with both old and new behaviors; but it is inevitable that once you
have everything working, someone will do an OS upgrade and blow away
your hard work. 

Since we use gcc on most platforms, we don't convert the headers ---
we just copy everything in /usr/include into /usr/local/lib/gcc-include
and make modifications there. In this manner, the stock development
system is independent of our custom "ANSIzed" version.  Other systems
may have flags that point the compiler to look in another directory
for your header directories.

	--jtc

-- 
J.T. Conklin	UniFax Communications Inc.
		...!{uunet,ubc-cs}!van-bc!jtc, jtc@wimsey.bc.ca

darcy@druid.uucp (D'Arcy J.M. Cain) (10/19/90)

In article <PDS.90Oct17102409@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
Seems an attribution was left off but looks like ?@van-bc.wimsey.bc.ca said:
>[] In article <PDS.90Oct15104036@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
>[] >Oh no! Not that!  *Never* *ever* *change* the standard libraries which
>
>[] At UniFax, we ANSIfy the development environment on all of our
>
>I'd say all this falls under the "unless they don't work" category! :-)  
>Even so, as has already been mentioned, there are probably better ways
>of doing it than changing the standard includes.
>
When I installed gcc on my system I modified it to look in /usr/newinclude
for headers and then in /usr/include if not found.  I then copied header
files into the new directory and modified them.  This leaves the original
header files untouched and in fact cc will still work if necessary using
the old header files.  What's the point of having an ANSI compiler if you
don't have the ANSI standard prototypes?

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   I support gun control.
West Hill, Ontario, Canada         |   Let's start with the government!
+ 416 281 6094                     |

bright@nazgul.UUCP (Walter Bright) (10/25/90)

In article <1990Oct02.132313.6659@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
<In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes:
<<It should be pointed out that in ANSI C free(NULL) is defined, and is
<<legal (any conforming implementation of free() must ignore being
<<passed a NULL pointer).
<While this is a true statement, I would never recommend that one take advantage
<of this feature.  If you know the variable is NULL don't pass it to free.
<The performance cost of the following statement:
<		if( ptr != NULL )
<			free(ptr);
<as opposed to:
<		free(ptr);
<will be unmeasurable in most, if not all, circumstances.  In addition, by
<adding the if() you get code that is portable across all implementations.


I'd prefer to use, on non-conforming implementations of free():

    #if NONCONFORMINGFREE
    #define free(p)	((p) && free(p))
    #endif

bright@nazgul.UUCP (Walter Bright) (10/25/90)

In article <335@bii.UUCP> gegu@bii.UUCP (Gerhard Gucher) writes:
<And as we all agree (I hope), the gain of portability to non ANSI
<systems is well worth it anyways. (Keep in mind, most in use systems
<don't carry ANSI yet ( Mess - DOS doesn't count as a system (:-) ).

In my experience, MS-DOS has the most advanced and polished programming
tools available on it. (Probably because of the intense competition
among programming tool vendors.) Practically all of the C compilers
for it that have any significance are nearly 100% ANSI conformant. I
can't say that for other systems I have used.

If other systems are so superior, why aren't their programming environments
up to the standards of the MS-DOS world?

arnold@audiofax.com (Arnold Robbins) (10/26/90)

In article <117@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
>I'd prefer to use, on non-conforming implementations of free():
>
>    #if NONCONFORMINGFREE
>    #define free(p)	((p) && free(p))
>    #endif

Note that this requires an ANSI compliant cpp or C compiler.  The original
discussion was about using an ANSI compiler with non-ansi libraries, so that's
fine, but if you try this macro on a pre-ansi cpp it'll recurse forever...
-- 
Arnold Robbins				AudioFAX, Inc. | Laundry increases
2000 Powers Ferry Road, #200 / Marietta, GA. 30067     | exponentially in the
INTERNET: arnold@audiofax.com Phone:   +1 404 933 7612 | number of children.
UUCP:	  emory!audfax!arnold Fax-box: +1 404 618 4581 |   -- Miriam Robbins

martin@mwtech.UUCP (Martin Weitzel) (10/26/90)

In article <280@audfax.audiofax.com> arnold@audiofax.com (Arnold Robbins) writes:
:In article <117@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
:>I'd prefer to use, on non-conforming implementations of free():
:>
:>    #if NONCONFORMINGFREE
:>    #define free(p)	((p) && free(p))
:>    #endif
:
:Note that this requires an ANSI compliant cpp or C compiler.  The original
:discussion was about using an ANSI compiler with non-ansi libraries, so that's
:fine, but if you try this macro on a pre-ansi cpp it'll recurse forever...

And NEVER use this macro with code that contains something like `free(*ptr++)'.

The latter construct is not unlikely, if there are arrays of pointers and
the space each pointer points to is dynamically allocated ...
-- 
Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83

henry@zoo.toronto.edu (Henry Spencer) (10/26/90)

In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
><... ( Mess - DOS doesn't count as a system (:-) ).
>
>If other systems are so superior, why aren't their programming environments
>up to the standards of the MS-DOS world?

Because they don't have 10^10 mindless lemmings buying them and thus
underwriting development costs.
-- 
The type syntax for C is essentially   | Henry Spencer at U of Toronto Zoology
unparsable.             --Rob Pike     |  henry@zoo.toronto.edu   utzoo!henry

floyd@hayes.ims.alaska.edu (Floyd Davidson) (10/27/90)

In article <1990Oct26.154315.26612@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
>><... ( Mess - DOS doesn't count as a system (:-) ).
>>
>>If other systems are so superior, why aren't their programming environments
>>up to the standards of the MS-DOS world?
>
>Because they don't have 10^10 mindless lemmings buying them and thus
>underwriting development costs.

Not to mention that "up to the standards of" seems to apply to mindless
programmers and their idea of "standards".  My perception of comparing
UNIX to MS-DOS as a programming environ is that one has a lot of frills
and no meat to it.  The latest "thing" for MS-DOS doesn't hold a candle
to what UNIX was 5 years ago, much less today, when it comes to getting
some work done.



-- 
Floyd L. Davidson   floyd@hayes.ims.alaska.edu    floydd@chinet.chi.il.us
Salcha, AK 99714    connected by paycheck to Alascom, Inc.
When *I* speak for them, one of us will be *out* of business in a hurry.

feg@moss.ATT.COM (Forrest Gehrke,2C-119,7239,ATTBL) (10/31/90)

In article <1990Oct26.154315.26612@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
>><... ( Mess - DOS doesn't count as a system (:-) ).
>>
>>If other systems are so superior, why aren't their programming environments
>>up to the standards of the MS-DOS world?
>
>Because they don't have 10^10 mindless lemmings buying them and thus
>underwriting development costs.
>-- 

And so far as programming in C is your desire, you have a choice
of working with a crippled OS or a crippled compiler.  Besides 
which the crippled compiler probably is working on a pricey 
computer with an similarly pricey OS.  Worse yet, even the
busted compiler often costs more than the computer with the
crippled OS! (;-))

Forrest Gehrke feg@moss.att.com
very pricey 

bright@nazgul.UUCP (Walter Bright) (11/01/90)

In article <280@audfax.audiofax.com> arnold@audiofax.com (Arnold Robbins) writes:
<In article <117@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
<>    #define free(p)	((p) && free(p))
<Note that this requires an ANSI compliant cpp or C compiler.  The original
<discussion was about using an ANSI compiler with non-ansi libraries, so that's
<fine, but if you try this macro on a pre-ansi cpp it'll recurse forever...

I've used similar constructs on a number of pre-ansi preprocessors, and
it worked fine (it did not recurse). When I implemented a preprocessor,
years before ansi, I made the mistake of it recursing. This was fixed
quickly...

gwyn@smoke.brl.mil (Doug Gwyn) (11/07/90)

In article <1990Oct26.154315.26612@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
>>If other systems are so superior, why aren't their programming environments
>>up to the standards of the MS-DOS world?
>Because they don't have 10^10 mindless lemmings buying them and thus
>underwriting development costs.

Also, the best UNIX software development environments are fully as nice
as the best MS-DOS ones, plus the other numerous benefits of using UNIX.

The worst UNIX software development environments are pretty ordinary,
but at least one has the other UNIX advantages to compensate for that.