[comp.lang.c] A tale of two C's.

ned@ghostwheel.UUCP (Ned Nowotny) (04/15/88)

At one time, C was an elegant, though imperfect, language.  The language
itself was purely control flow and data definition.

Now, however, X3J11, in the interest of runaway optimization, has exploded
the name space of the language by reserving a whole host of function, macro,
and data names.  While it is true that almost everyone wants standard libraries
with their C compilers which match the libraries developed over the years on
systems running the various flavors of Unix, I can't believe a majority of C
programmers want these library definitions rolled into the language.

ANSI C looks more like Pascal, Ada, Modula (pick a number), etc. every day.
Maybe we do need D or its equivalent.  Or maybe, there will be two languages
supported in the market place by, possibly competing, vendors -- C and ANSI-C.

That's it.  There are two languages involved here: ANSI-C, standardized by
X3J11 (thank you), and C, not quite standardized by K&R (possibly the second
edition).

Perhaps this is the best of all possible worlds after all.
-- 

Ned Nowotny (ned@ghostwheel.aca.mcc.com.UUCP)

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/15/88)

In article <152@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>Now, however, X3J11, in the interest of runaway optimization, has exploded
>the name space of the language by reserving a whole host of function, macro,
>and data names.  While it is true that almost everyone wants standard libraries
>with their C compilers which match the libraries developed over the years on
>systems running the various flavors of Unix, I can't believe a majority of C
>programmers want these library definitions rolled into the language.

I don't believe you could have studied the proposed standard before posting
this nonsense.  How would "exploding the name space" possible serve the
interest of "runaway optimization"?  X3J11 introduced only three names
that could be considered to be motivated by considerations of optimization,
namely the three type qualifiers.  One of them has a chance of being withdrawn
next week, another's main purpose was to permit ROMable data generation, and
the third's main purpose is to DISABLE optimization.

As to the headers, ANSI C provides a much more controlled name space than
traditional practice (which varied widely among implementations).  In fact
the cleanliness of this name space became a substantial issue between X3J11
and IEEE 1003.1, who were prohibited from introducing additional names via
the standard headers.  The library functions that are being standardized for
use in hosted environments are the ones that in fact programmers have wanted
to have available everywhere, rather than having to carry around their own
private libraries (which would not be able to implement good system interfaces
in a portable manner anyway).  There have been a few new functions created in
order to support programming in an "internationalized" environment, but the
vast majority were based on common (but not universal) existing practice.  In
fact my pre-ANSI C applications depend on the availability of most of these
library functions; I'll be glad to have them become universally available.

Definitions such as those in <limits.h> (which is NOT an X3J11 invention)
only take effect if you include the header, and in any case the totality
of the standardized symbols is relatively small and well-defined.  Since
there are no vendor-specific symbols (other than a few special forms that
can be easily avoided) defined by including standard headers in an ANSI C
conforming environment, there is much less to worry about when developing
maximally portable applications.  Anyone who has ported many applications
across widely divergent C environments should be able to appreciate what an
improvement this will be!

If you really want a "free-standing" environment (free of library functions),
that is one of the two environments provided for in the standard.

jss@hector.UUCP (Jerry Schwarz) (04/20/88)

In article <152@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>
>Now, however, X3J11, in the interest of runaway optimization, has exploded
>the name space of the language by reserving a whole host of function, macro,
>and data names.  While it is true that almost everyone wants standard libraries
>with their C compilers which match the libraries developed over the years on
>systems running the various flavors of Unix, I can't believe a majority of C
>programmers want these library definitions rolled into the language.
>

What the dpANSI standard does is limit implementors in the names they
can remove from the user name space.  This is not an explosion of the
name space, but a control of it.  In the past many implementations
would give core dumps when the user wrote

	void write(n) int n ; { printf("%d\n",n) ; }

because "printf" called "write".  This will no longer be allowed.

Jerry Schwarz
Bell Labs, Murray Hill

ned@ghostwheel.UUCP (Ned Nowotny) (04/21/88)

In article <7691@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <152@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>>Now, however, X3J11, in the interest of runaway optimization, has exploded
>>the name space of the language by reserving a whole host of function, macro,
>>and data names.
>
>I don't believe you could have studied the proposed standard before posting
>this nonsense.  How would "exploding the name space" possible serve the
>interest of "runaway optimization"?

Of course, the newly "reserved" function, macro, and data names are reserved
primarily to support portability.  However, there have been more then a few
comments in this newsgroup supporting the idea that "optimizing" compilers
should recognize standard functions like strcpy() and replace their invocation
with "semantically equivalent" in-line code.  Treating strcpy(), or any other
standard library function, in this manner effectively adds these functions to
the implementation's set of keywords.

While standardizing the library functions and header files is a positive boon
to portability, implementors should not take X3J11's reservation of these
element names as a license to roll the handling of functions or macros which
match the standard names into the compiler.  When portability is not an issue,
a programmer should be free to use his or her own implementation of a standard
library function.

Frankly, an "optimizing" link editor which could inline short functions based
on metrics provided by the programmer would be preferable.  Such a link editor
would also be less likely to link in "dead" code and could possibly obviate
the need for prototypes if sufficient information was provided in the symbol
tables generated by the compiler.  (At least, we might be able to get away
from the maintenance problem caused by effectively requiring multiple
declarations of the same function.)
-- 

Ned Nowotny (ned@ghostwheel.aca.mcc.com.UUCP)

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/24/88)

In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>When portability is not an issue, a programmer should be free to use
>his or her own implementation of a standard library function.

I think you need to explain why this is considered desirable.

Many of the library functions are likely to have secret internal
interfaces to others, so you cannot implement them correctly in a
portable application.  Others, such as strcpy(), will be implemented
more efficiently in general in the standard library than in your
application.  If you try to speed them up by providing subset
functionality, you may break other library routines that need to use
these with full functionality.

Whenever the C library is inappropriate, you should code for the
"freestanding" environment rather than the "hosted" environment.
Then you can define almost all functions as you see fit without
breaking anything.  Of course you may wish to steal some functions
from the hosted-environment library, but whether or not that will
work depends on details of the specific implementation, among other
things.

drs@bnlux0.bnl.gov (David R. Stampf) (04/25/88)

In article <7750@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>>When portability is not an issue, a programmer should be free to use
>>his or her own implementation of a standard library function.
>
>I think you need to explain why this is considered desirable.
>
>Many of the library functions are likely to have secret internal
>interfaces to others, so you cannot implement them correctly in a
>portable application.  Others, such as strcpy(), will be implemented
>more efficiently in general in the standard library than in your
>application.  If you try to speed them up by providing subset
>functionality, you may break other library routines that need to use
>these with full functionality.
>

Even when portability is and issue - I think that the C view of libraries
is meant to be taken advantage of!

I have frequently found the need to chuck some of the standard library
routines in favour of locally written routines - more often that not, these
are the memory allocation routines.  Sometimes it is to gain a *huge*
performance gain (in one example I didn't need the full generality that malloc
gave me, since I was always allocating fixed length blocks, so I wrote my own
that took advantage of the machine that I was running on (Mac) and other times
it is to take advantage of some unique aspect of the machine that I was working
on (parallel processing with shared memory).  In either case, I wanted the
code to be portable to { wide variety of machines that may have very different
architectures.  Those machines may pay a performance penalty, but not the
ultimate penalty of having to rewrite bizarre library routines.

In these cases, you cannot export your custom library routines - but have to
allow the default library to kick in.  (It also makes debugging a *lot*
easier in most cases).

	< dave.

dave@sdeggo.UUCP (David L. Smith) (04/26/88)

In article <7750@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
> >When portability is not an issue, a programmer should be free to use
> >his or her own implementation of a standard library function.
> 
> I think you need to explain why this is considered desirable.

The one that I have seen most commonly is a replacement malloc() 
routine.  For example, the Bourne shell replaces malloc() with its 
own version so that it can have a stack interspersed with the heap.

Whether or not this was necessary I'm not sure, but it does seem 
like the easiest way to implement it.  The stack is set at the top 
of memory; when it grows to big it generates a segmentation violation 
which causes malloc() to allocate more memory and relocate the stack 
at the top of memory.  The other alternative, if implemented with 
vanilla malloc, would be to give some memory to the stack and then 
monitor it everytime something was put on the stack to make sure it 
didn't overflow.  Relying on the system to tell you when you're
out of space is a lot easier.

The Bourne shell's malloc() also provides a good reason not to 
replace library routines with your own lightly.  In at least one 
version of sh (I believe it is the V.2 version), it doesn't work 
quite right.  If this malloc() package had been used more extensively 
(as the library routines are) this bug wouldn't have existed for long.  
(BTW, the Celerity version of sh has this fixed, plug, plug :-) )

Doug mentions "hidden interfaces" between library routines.  These 
don't sound like a good idea and probably should be avoided.  After 
all, occasionally library routines have bugs in them which the vendor 
is unwilling or unable to fix.  A binary-license site with a smart 
programmer can come up with a functional replacement for a library 
routine, sans bug, but not if these hidden interfaces exist.

In short, I feel that being able to replace library routines is 
necessary for two reasons:  To achieve a difference in functionality 
without recoding the rest of the library routines which depend on the 
one you want to change and to fix bugs when you don't have a source 
license.
-- 
David L. Smith
{sdcsvax!jack,ihnp4!jack, hp-sdd!crash, pyramid, uport}!sdeggo!dave
sdeggo!dave@amos.ling.edu 
Sinners can repent, but stupid is forever.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/27/88)

In article <195@sdeggo.UUCP> dave@sdeggo.UUCP (David L. Smith) writes:
-Whether or not this was necessary I'm not sure, but it does seem 
-like the easiest way to implement it.  The stack is set at the top 
-of memory; when it grows to big it generates a segmentation violation 
-which causes malloc() to allocate more memory and relocate the stack 
-at the top of memory.  The other alternative, if implemented with 
-vanilla malloc, would be to give some memory to the stack and then 
-monitor it everytime something was put on the stack to make sure it 
-didn't overflow.  Relying on the system to tell you when you're
-out of space is a lot easier.

It also doesn't work right on some systems such as MC68000s.
Several of us spent a lot of time getting this fixed, and the BRL
version of the Bourne shell can be configured to take the tedious
but correct approach instead of relying on the SIGSEGV kludge.

I think it serves as a good illustration of what can go wrong with
preempting library routines rather than cooperating with them.

karl@haddock.ISC.COM (Karl Heuer) (04/27/88)

In article <195@sdeggo.UUCP> dave@sdeggo.UUCP (David L. Smith) writes:
>>In article <154@ghostwheel.UUCP> ned@ghostwheel (Ned Nowotny) writes:
>>>When portability is not an issue, a programmer should be free to use
>>>his or her own implementation of a standard library function.

I don't see that there's any problem.  In K&R C, one can replace a library
function, and the result is not portable.  In ANSI C, this continues to be
true.  No doubt some vendors will continue to supply implementations which
will do what you expect even in the face of such a construct.

>The one that I have seen most commonly is a replacement malloc()
>routine.  For example, the Bourne shell replaces malloc() with its
>own version so that it can have a stack interspersed with the heap.

And it's a pain trying to port sh to implementations that don't conform to its
bogus assumptions.  I've been there.

>Doug mentions "hidden interfaces" between library routines.  These
>don't sound like a good idea and probably should be avoided.

Let's consider the simple kind of "hidden interface".  On one implementation,
printf() works by calling fputc().  On another, it doesn't.  Both are correct,
and hence the result of writing your own fputc() is undefined.  If you don't
like that situation, you'd have to specify which implementation is illegal.
This would be an otherwise-unnecessary restriction on the implementor, and I
don't think it's justifiable.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

simon@its63b.ed.ac.uk (ECSC68 S Brown CS) (04/27/88)

In article <195@sdeggo.UUCP> dave@sdeggo.UUCP (David L. Smith) writes:
>>In article <7750@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
>
>The one that I have seen most commonly is a replacement malloc() 
>routine.  For example, the Bourne shell replaces malloc() with its 
>own version so that it can have a stack interspersed with the heap.
>
>Whether or not this was necessary I'm not sure, but it does seem 
>like the easiest way to implement it.  The stack is set at the top 
>of memory; when it grows to big it generates a segmentation violation 
>which causes malloc() to allocate more memory and relocate the stack 
>at the top of memory.  The other alternative, if implemented with 
>vanilla malloc, would be to give some memory to the stack and then 
>monitor it everytime something was put on the stack to make sure it 
>didn't overflow.  Relying on the system to tell you when you're
>out of space is a lot easier.
>

This "relying on the system" technique isn't really the main reason why
sh has it's own malloc - after all, on 68000-based systems, growing-on-sigsegv
doesn't work anyway, but sh still needs it's own malloc there. The real
reason for it is that it provides the possibility of "open-ended" malloc'ing,
where you don't know how much space is required at the time when you call
malloc. For example,
	p = q = open_ended_malloc();
	while (something())
		*q++ = blob();
	close_malloc(q);
will give you a pointer "p" pointing to everything you put on, up to the call
of close_malloc(). It certainly beats having to do it all with unpleasant
linked-lists all the time. I'm surprised no other programs use this technique,
it seems so useful!

	Simon.

-- 
--------------------------------------------------
| Simon Brown                                    |
| Laboratory for Foundations of Computer Science |
| Department of Computer Science                 |
| University of Edinburgh, Scotland, UK.         |
--------------------------------------------------
 UUCP:  uunet!mcvax!ukc!lfcs!simon
 ARPA:  simon%lfcs.ed@nss.cs.ucl.ac.uk
 JANET: simon@uk.ac.ed.lfcs

davidsen@steinmetz.ge.com (William E. Davidsen Jr) (04/27/88)

In article <195@sdeggo.UUCP> dave@sdeggo.UUCP (David L. Smith) writes:
>In article <7750@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
>> In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>> >When portability is not an issue, a programmer should be free to use
>> >his or her own implementation of a standard library function.
>> 
>> I think you need to explain why this is considered desirable.
>
>The one that I have seen most commonly is a replacement malloc() 
>routine.  For example, the Bourne shell replaces malloc() with its 

  I proposed to dpANS that the library be broken into "sections" which
were independent.  That is you could assume that anything in one section
used only documented calls to anything in another section, but there was
an assumption that if you changed anything in one section that you might
have to replace all of it.

  As I recall I wanted to separate the math, io, and a few other
sections. I don't remember the discussion, but the idea was not adopted
at that time.

  My desire is to replace print with something which doesn't take up a
lot of space for F.P. routines if I will call it only with integers.
Suggestions to the contrary, this would reduce the size of the program,
and putting in explicit error messages would make it grow as large as
the math routines (in many cases).

  I just renamed my routine and use a
	#define print my_print
to generate the calls. This leaves the code easily portable.
-- 
	bill davidsen		(wedu@ge-crd.arpa)
  {uunet | philabs | seismo}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

tps@chem.ucsd.edu (Tom Stockfisch) (04/28/88)

In article <474@bnlux0.bnl.gov> drs@bnlux0.UUCP (David R. Stampf) writes:
>>In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>>>When portability is not an issue, a programmer should be free to use
>>>his or her own implementation of a standard library function.

>I have frequently found the need to chuck some of the standard library
>routines in favour of locally written routines...
>(in one example I didn't need the full generality that malloc
>gave me, since I was always allocating fixed length blocks, so I wrote my own
>that took advantage of the machine that I was running on (Mac)...

Why would you want to call a function "malloc()" if it does not do the
same thing that the malloc(3) man page says malloc() does?

>... I wanted the
>code to be portable to a wide variety of machines that may have very different
>architectures...
>In these cases, you cannot export your custom library routines - but have to
>allow the default library to kick in.
>	< dave.

So write something like

	# ifdef MAC
		BLOCK_T *	/* new memory */
		block_alloc( nblocks )
		{
			[fast, unportable stuff here]
		}
	# else
		BLOCK_T *	/* new memory */
		block_alloc( nblocks )
		{
			return	(BLOCK_T *)malloc( nblocks*sizeof(BLOCK_T) );
		}
	# endif

I would find it *very* confusing to read code in which malloc() (or any
other standard library function) did something besides/instead of what
it is supposed to.
-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu

nevin1@ihlpf.ATT.COM (00704a-Liber) (04/28/88)

In article <195@sdeggo.UUCP> dave@sdeggo.UUCP (David L. Smith) writes:
>In short, I feel that being able to replace library routines is 
>necessary for two reasons:  To achieve a difference in functionality 
>without recoding the rest of the library routines which depend on the 
>one you want to change and to fix bugs when you don't have a source 
>license.

I disagree with both these reasons.  First, by replacing a library routine
with your own you might still have to recode the rest of the library
routines which depend on the one you want to change.  Although your
programs should make the assumption that they can only be dependent on the
*description* of a library and independent of its' implementation, the
implementor of the library routine is not bound by these restrictions.
Also, you get name-space violations (how does cc know which function to
call?  Should it always call the new one??  If you define a third one,
which one should we call??) and will very likely have
problems using shared libraries.

Point 2:
If you want to change library routines for your program only, use
statements like

	#define	strcpy(s1, s2)	my_string_copy(s1, s2)

which makes this very explicit, and you don't need a source license.

-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah

markb@sdcrdcf.UUCP (Mark Biggar) (04/28/88)

In article <193@chem.ucsd.EDU> tps@chem.ucsd.edu (Tom Stockfisch) writes:
>In article <474@bnlux0.bnl.gov> drs@bnlux0.UUCP (David R. Stampf) writes:
>>>In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>>>>When portability is not an issue, a programmer should be free to use
>>>>his or her own implementation of a standard library function.
>>I have frequently found the need to chuck some of the standard library
>>routines in favour of locally written routines...
>>(in one example I didn't need the full generality that malloc
>>gave me, since I was always allocating fixed length blocks, so I wrote my own
>>that took advantage of the machine that I was running on (Mac)...
>Why would you want to call a function "malloc()" if it does not do the
>same thing that the malloc(3) man page says malloc() does?
>
>I would find it *very* confusing to read code in which malloc() (or any
>other standard library function) did something besides/instead of what
>it is supposed to.

Actually malloc is a case where rolling your own can provide emormous
speed up in your program.  Do you realize just how much overhead is added
to malloc just so you can free things.  I wrote a large (20000 lines)
program that used malloc everywhere.  The longer it ran the slower it got.
On profiling it I discovered that the program was spending 47% of its time
in malloc!  The program never freed anything, so I replaced malloc with a
much simpler one that just gave me some memory and didn't do any of the
screwy thing that the regular malloc does (like chase down a link list of
every block ever allocated to see if you might just have freed a block big
enough to honor the the current request).  This gave me a 40%+ speedup in
the program and the program stopped getting slower.  By putting the simple
replacement malloc in its own file, I made the program just as protable as
befor because you didn't have to use my malloc. (Altough mine would work
correctly on both bsd and SV type unix systems.)

Mark Biggar
{allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb
markb@rdcf.sm.unisys.com

bright@Data-IO.COM (Walter Bright) (04/29/88)

In article <10604@steinmetz.ge.com> davidsen@kbsvax.steinmetz.UUCP (William E. Davidsen Jr) writes:
<  My desire is to replace print with something which doesn't take up a
<lot of space for F.P. routines if I will call it only with integers.
<Suggestions to the contrary, this would reduce the size of the program,
<  I just renamed my routine and use a
<	#define print my_print
<to generate the calls. This leaves the code easily portable.

The technique I use is to:
	o Make the floating point formatting portion of printf() an internal
	  function call in a separate file.
	o Collect all the names of floating point functions, such as
	  ecvt(), atof(), _dblmul(), etc.
	o Define all these names in a new module called intonly.c, and have
	  them all resolve to a function which prints an error message and
	  exits.
	o Therefore, when linking, including intonly.obj in the object list
	  will produce an integer-only program without the overhead of all
	  those floating point routines.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (04/29/88)

In article <474@bnlux0.bnl.gov> drs@bnlux0.UUCP (David R. Stampf) writes:
>(in one example I didn't need the full generality that malloc
>gave me, since I was always allocating fixed length blocks, so I wrote my own
>that took advantage of the machine that I was running on (Mac) ...

The correct way to do this is to write your own MyAlloc() function
that calls on the library malloc() to obtain big chunks of heap which
it then subdivides.  You have no way of knowing what one of the C
library routines may need to malloc(), so it is a mistake to replace
malloc() with one that does not have the full semantics.  On unusual
architectures it is a mistake to replace it, period.

drs@bnlux0.bnl.gov (David R. Stampf) (04/30/88)

In article <193@chem.ucsd.EDU> tps@chem.ucsd.edu (Tom Stockfisch) writes:
>In article <474@bnlux0.bnl.gov> drs@bnlux0.UUCP (David R. Stampf) writes:
>>>In article <154@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes:
>>>>When portability is not an issue, a programmer should be free to use
>>>>his or her own implementation of a standard library function.
>
>>I have frequently found the need to chuck some of the standard library
>>routines in favour of locally written routines...
>>(in one example I didn't need the full generality that malloc
>>gave me, since I was always allocating fixed length blocks, so I wrote my own
>>that took advantage of the machine that I was running on (Mac)...
>
>Why would you want to call a function "malloc()" if it does not do the
>same thing that the malloc(3) man page says malloc() does?
>

Of course I wouldn't want to define a function called printf that allocates
memory, or sin that did sqrt.  The point is that one might like to have
a more efficient version (for the application at hand) than the malloc
provided in the library.  My versions of malloc *always* behaved exactly
like the malloc(3).  It might be totally acceptable to have a routine called
emalloc() or must_malloc() or some such that *must* allocate memory and in
facts checks the return value for you.


>>... I wanted the
>>code to be portable to a wide variety of machines that may have very different
>>architectures...
>>In these cases, you cannot export your custom library routines - but have to
>>allow the default library to kick in.
>>	< dave.
>
>So write something like
>
>	# ifdef MAC
>		BLOCK_T *	/* new memory */
>		block_alloc( nblocks )
>		{
>			[fast, unportable stuff here]
>		}
>	# else
>		BLOCK_T *	/* new memory */
>		block_alloc( nblocks )
>		{
>			return	(BLOCK_T *)malloc( nblocks*sizeof(BLOCK_T) );
>		}
>	# endif
>


This is better???  I find it 1) ugly, 2) error prone (when you start to write
code for two different machines using ifdefs, there is a tendency to debug
only one branch of the #ifdef and leave the other for some other character
to find)  and 3) makes the malloc version even less efficient - now you make
2 function calls per malloc rather than one.  Finally, when the programmer
is working on a remote section of the code he is likely to either forget about
this function and call malloc, forget what the new program was called, or
see a reference to block_malloc, and not really associated the malloc function
with it.  Also, it is very unlikely that a programmer would go to the trouble
of making a new manual page for block_malloc.


>I would find it *very* confusing to read code in which malloc() (or any
>other standard library function) did something besides/instead of what
>it is supposed to.
>-- 
>
>|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu


Me too.  That's why I would want it to perform the save function as malloc,
only to do it in a slightly different fashion.

	< dave


*fodder for the news program *
*fodder for the news program *
*fodder for the news program *
*fodder for the news program *
*fodder for the news program *
*fodder for the news program *
*fodder for the news program *
*fodder for the news program *
*fodder for the news program *

bts@sas.UUCP (Brian T. Schellenberger) (05/02/88)

There have been numerous postings back and forth about whether or not
one should replace library routines.  It seems to me to be much easier to get
the legitimate benifits of such replacement, assuming there are any, without
being unportable than most people seem to assume.

First of all, it is clearly unportable and dangerous to replace the versions
of the library routines used by other library routines, since there is no
way to know what the inter-relationships of these routines may be on various
machines.  This doesn't preclude you from doing whatever you want if the code
is for a single machine and single version of the compiler and operating 
system, but in such a case portable code (and the ANSI draft) should be of
no concern anyway.

Second of all, if you don't like the normal memory allocation routines, you
can write and use your own quite portably.

Third, if you *really* can't stand to change the name by which you call the
routines, it is pretty safe to 
	#define malloc  mymalloc

Of course, strictly speaking, the ANSI draft states that all library routine
names are reserved words, so this might be unportable (though I doubt it will
really fail anyplace).  So it would be safer to retrain your fingers to 
type "myalloc" instead of "malloc".  If you want it to be the same even on
machines whose native "malloc" you like, simply
	#if I_LIKE_IT
	#define myalloc malloc
	#endif
-- 
                                                         --Brian.
(Brian T. Schellenberger)				 ...!mcnc!rti!sas!bts

. . . now at 2400 baud, so maybe I'll stop bothering to flame long includes.

ok@quintus.UUCP (Richard A. O'Keefe) (05/03/88)

In article <488@sas.UUCP>, bts@sas.UUCP (Brian T. Schellenberger) writes:
> First of all, it is clearly unportable and dangerous to replace the versions
> of the library routines used by other library routines...
Sometimes that is exactly what you want.  For example, what is the good of
replacing the malloc() family by something with the same interface but a
much better implementation if this doesn't catch malloc() calls from stdio?
If you _don't_ want to catch library calls, there isn't any need to 
REdefine any library function.  But yes, it is non-portable, and can be
dangerous (it's usually ok under UNIX and more trouble than it's worth under
VMS).

It's worth noting that exactly this technique is an offical part of the
System V library interface (see 'matherr').

A library _could_ be structured into "facilities" (malloc, stdio, math,
signal&longjmp, ...) such that each facility was defined to use only the
public interface of the other facilities.  It would then be safe to
replace an entire facility with your own code.  There is nothing in the
dpANS to prohibit a vendor doing this; code which relied on a well-structured
library would be non-portable but no longer dangerous.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/03/88)

In article <488@sas.UUCP> bts@sas.UUCP (Brian T. Schellenberger) writes:
>Second of all, if you don't like the normal memory allocation routines, you
>can write and use your own quite portably.

The only safe way to do this is to make your private memory allocator
obtain heap space from the standard C library allocator (malloc).

gwyn@brl-smoke.ARPA (Doug Gwyn ) (05/03/88)

In article <924@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>It's worth noting that exactly this technique is an offical part of the
>System V library interface (see 'matherr').

matherr() was intended to be replaced by user code (and so documented)
as a deliberate aspect of its design.  None of the other library routines
is obliged to support such perversion.

nevin1@ihlpf.ATT.COM (00704a-Liber) (05/04/88)

In article <924@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
>In article <488@sas.UUCP>, bts@sas.UUCP (Brian T. Schellenberger) writes:
>> First of all, it is clearly unportable and dangerous to replace the versions
>> of the library routines used by other library routines...

>Sometimes that is exactly what you want.  For example, what is the good of
>replacing the malloc() family by something with the same interface but a
>much better implementation if this doesn't catch malloc() calls from stdio?

Suppose there are two routines: malloc() and _malloc().  malloc() is the
routine for heap allocation for both internal library calls and external
(programmer) calls.  _malloc() is strictly for internal library use only
(for example:  maybe malloc() does some checking of the heap while
_malloc() just does the allocating).

You come along and replace malloc() with your own function.  The library
routines that call malloc() are caught while the ones that call _malloc()
aren't.  There is no way for you to know whether or not you have replaced
_all_ the calls to the malloc family.

>A library _could_ be structured into "facilities" (malloc, stdio, math,
>signal&longjmp, ...) such that each facility was defined to use only the
>public interface of the other facilities.  It would then be safe to
>replace an entire facility with your own code.  There is nothing in the
>dpANS to prohibit a vendor doing this; code which relied on a well-structured
>library would be non-portable but no longer dangerous.

Yes, but there is nothing in dpANS which _requires_ this.  Nor do I think
it should be required.  If a compiler writer decides to hand code in
assembler all the library routines so that it produces the tightest,
fastest possible code he should be allowed to do so (in which case internal
subroutines may only be assembler JMP statements which do not have nearly
as much overhead as normal C function calls).

-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah

ok@quintus.UUCP (Richard A. O'Keefe) (05/05/88)

In article <7821@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
: In article <924@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
: >It's worth noting that exactly this technique is an offical part of the
: >System V library interface (see 'matherr').
: 
: matherr() was intended to be replaced by user code (and so documented)
: as a deliberate aspect of its design.  None of the other library routines
: is obliged to support such perversion.

Yes, I know that.  I guess it's a mistake to try to be too succinct in news.
matherr() is a compellingly good(bad) example of how _not_ to design an
error-handling interface.  I thought I should provide some argument against
replacing library routines as well as some for.

ok@quintus.UUCP (Richard A. O'Keefe) (05/05/88)

In article <4626@ihlpf.ATT.COM>, nevin1@ihlpf.ATT.COM (00704a-Liber) writes:
> >A library _could_ be structured into "facilities" (malloc, stdio, math,
> >signal&longjmp, ...) such that each facility was defined to use only the
> >public interface of the other facilities.

> Yes, but there is nothing in dpANS which _requires_ this.  Nor do I think
> it should be required.

I did not say that the dpANS requires it, or that it should require it,
or that anyone should require it.  I merely outlined a scheme which _would_
make it safe for users to replace library facilities.  The scheme is nothing
more than good software engineering practice.  I don't know whether any C
implementation actually does that (at least the version of UNIX I'm using
doesn't have a hidden _malloc()).

> If a compiler writer decides to hand code in
> assembler all the library routines so that it produces the tightest,
> fastest possible code he should be allowed to do so. (in which case internal
> subroutines may only be assembler JMP statements which do not have nearly
> as much overhead as normal C function calls).

He should also be allowed to go broke.  I'd much rather he spent his time
figuring out how to make _my_ code go fast.  I would be _especially_
forgiving to a compiler writer who had decided to put the effort into making
normal C function calls fast.  [e.g. special treatment for leaf functions,
maybe even #pragma inline(...).]