[comp.std.c] ANSI C standard library

pipkinsj@cpqhou.uucp (Jeff Pipkins @Adv Dev@SE hou ) (04/12/91)

I'm looking for an ANSI C implementation of the ANSI C standard library.
I'd settle for a K&R C implementation of anything close.  Most available
libraries I've seen are about 40% to 60% ASM lang, but I need C.

Can anybody tell me about a good source for this sort of thing?

-- 
Jeff D. Pipkins  (pipkinsj@cpqhou.se.hou.COM  or  uunet!cpqhou!pipkinsj)

Disclaimer: My opinions do not necessarily reflect those of my employer.
"Things should be made as simple as possible, but no simpler" --Einstein

barmar@think.com (Barry Margolin) (04/12/91)

In article <1991Apr11.185038.108@cpqhou.uucp> uunet!cpqhou!pipkinsj (Jeff Pipkins @Adv Dev@SE hou ) writes:
>I'm looking for an ANSI C implementation of the ANSI C standard library.

There are many functions in the standard C library that can't be
implemented in ANSI C, because they are interfaces to OS-dependent
facilities.  For instance, fopen() has to call something analogous to
Unix's open(), signal() has to do whatever is necessary to hook into the
system's interrupt mechanism, system() has to call a system-dependent
shell routine, and malloc() has to use the OS's memory management facility.

The math and string functions can be implemented portably, but they're
usually implemented in assembler for performance reasons.
--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

lewine@cheshirecat.webo.dg.com (Donald Lewine) (04/16/91)

In article <1991Apr11.185038.108@cpqhou.uucp>, pipkinsj@cpqhou.uucp (Jeff Pipkins @Adv Dev@SE hou ) writes:
|> I'm looking for an ANSI C implementation of the ANSI C standard library.
|> I'd settle for a K&R C implementation of anything close.  Most available
|> libraries I've seen are about 40% to 60% ASM lang, but I need C.
|> 
|> Can anybody tell me about a good source for this sort of thing?
|> 

It can not be done!  The reason that many of these things are in
the ANSI library is that they can not ve written in portable C.
If there is a library that is 60% ANSI conforming C, you are doing
very well.

--------------------------------------------------------------------
Donald A. Lewine                (508) 870-9008 Voice
Data General Corporation        (508) 366-0750 FAX
4400 Computer Drive. MS D112A
Westboro, MA 01580  U.S.A.

uucp: uunet!dg!lewine   Internet: lewine@cheshirecat.webo.dg.com

gwyn@smoke.brl.mil (Doug Gwyn) (04/16/91)

In article <1991Apr11.185038.108@cpqhou.uucp> uunet!cpqhou!pipkinsj (Jeff Pipkins @Adv Dev@SE hou ) writes:
>I'm looking for an ANSI C implementation of the ANSI C standard library.
>Can anybody tell me about a good source for this sort of thing?

P.J. Plauger has written such a book, and I think the source code is
available in machine-readable form for a reasonable fee.  The book
should be available any day now.

steve@taumet.com (Stephen Clamage) (04/19/91)

lewine@cheshirecat.webo.dg.com (Donald Lewine) writes:

>In article <1991Apr11.185038.108@cpqhou.uucp>, pipkinsj@cpqhou.uucp (Jeff Pipkins @Adv Dev@SE hou ) writes:
>|> I'm looking for an ANSI C implementation of the ANSI C standard library...

>It can not be done!  The reason that many of these things are in
>the ANSI library is that they can not ve written in portable C.
>If there is a library that is 60% ANSI conforming C, you are doing
>very well.

This is simply untrue.  (Those who say a thing cannot be done should
stay out of the way of those who are doing it...)

We have a complete hosted ANSI C library written in ANSI C.  It depends
on operating system support (system calls) for those features which
interact with the operating system.  There are about 10 of these calls.
If a system does not provide the support, the C library features are
not available anyway (how do you open a file if there is no file system
and no "open-file" system call?).

There is one assembler source file for ANSI C functions: setjmp/longjmp.

There are a very few assembler files which provide low-level machine
functions, such as detecting the presence of a math co-processor,
providing support for the debugger, and so on.

On some systems to which we port, the system calls are known by different
names or have different calling sequences than expected in the portable C
code.  In such cases, we provide a translation function, usually in
assembler for efficiency.

We have used our library on BSD Unix, System V Unix, VAX/VMS, MS/DOS,
CP/M, OS/9.  We have used in on a variety of computer architectures:
MC680x0, VAX, SPARC, MIPS, ix86, i8085, MC6809.  Some of our
customers have ported the library to other systems.

Considering there are over 150 functions in the library written in ANSI
C, and less than a dozen tiny functions which are machine-specific, I'd
say we do considerably better than 60%.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

ccplumb@rose.waterloo.edu (Colin Plumb) (04/20/91)

>> In article <1991Apr11.185038.108@cpqhou.uucp>, pipkinsj@cpqhou.uucp (Jeff Pipkins @Adv Dev@SE hou ) writes:
>>> I'm looking for an ANSI C implementation of the ANSI C standard library...

> lewine@cheshirecat.webo.dg.com (Donald Lewine) writes:
>> It can not be done!  The reason that many of these things are in
>> the ANSI library is that they can not ve written in portable C.
>> If there is a library that is 60% ANSI conforming C, you are doing
>> very well.

steve@taumet.com (Stephen Clamage) wrote:
> This is simply untrue.  (Those who say a thing cannot be done should
> stay out of the way of those who are doing it...)
>
> We have a complete hosted ANSI C library written in ANSI C.  It depends
> on operating system support (system calls) for those features which
> interact with the operating system.  There are about 10 of these calls.
> If a system does not provide the support, the C library features are
> not available anyway (how do you open a file if there is no file system
> and no "open-file" system call?).
>
> There is one assembler source file for ANSI C functions: setjmp/longjmp.

Okay, time to start in on the language legalese.
A "strictly conforming" program obeys all the rules of the ANSI C
standard.  A "conforming" compiler will compile all strictly conforming
programs (subject to limits like memory usage).  A "conforming" program
is one that is accepted by a conforming compiler.  It may use any extensions
the compiler wishes to provide, as long as those won't foul up strictly
conforming C programs.  Most of gcc's extensions fall into this category.

Anyway, it's easy to write a reasonably portable, conforming C library.
That is, one that will compile on a number of ANSI-conformant C compilers
and work as intended.  There are however, a number of functions in the
C library that cannot be implemented, efficiently or perhaps at all, in
*strictly* conforming C.  setjmp/longjmp is the obvious one.  memmove is
the standard example of somethig that's doable in strictly conforming
ANSI C, but not efficiently.  The problem with memmove is that you have
to handle overlapping properly, and comparisons between pointers into
different objects are not guaranteed comparable by the relational
(<, <=, >, >=) operators in ANSI C.  Thus, you have to use equality
tests (which are guaranteed to work) to check to see if any byte in the
source is also a byte in the destination.

This is, of course, disgusting, and nobody would actually write it that way.
But the reason for those odd guarantees is that they simplify doing far
pointer arithmetic on 80x86 machines, and so have some very common
applications.  (True, there the relational operators will just gove bogus
results on pointers to different objects, which doesn't hurt much, but
some hypothetical fascist capability machine might give a run-time error.)

So, the upshot of it all is:
- A large fraction of the ANSI C library can't be written in *strictly
conforming* ANSI C.  This was usually the reason of putting it in the
library in the first place - without the library function, the programmer
would be up the creek.  Thus, if you want a strictly conforming (guaranteed
to work on any ANSI C compiler) C library, you're out of luck.
- However, most people's ANSI C libraries are mostly or even wholly
C.  It's just that it's not strictly conforming C, as it relies on
certain properties of the compiler that are not guaranteed by the ANSI
C standard.  If you're willing to live with extra constraints, there
are a number of non-strictly conforming C libraries floating around
(admittedly mostly commercial).

Is that fairly clear?
-- 
	-Colin

steve@taumet.com (Stephen Clamage) (04/21/91)

ccplumb@rose.waterloo.edu (Colin Plumb) writes:

>- A large fraction of the ANSI C library can't be written in *strictly
>conforming* ANSI C.  This was usually the reason of putting it in the
>library in the first place - without the library function, the programmer
>would be up the creek.  Thus, if you want a strictly conforming (guaranteed
>to work on any ANSI C compiler) C library, you're out of luck.

In the full posting you mentioned only setjmp and longjmp as
functions which cannot be written in strictly-conforming C, and
memmove which cannot be written efficiently in strictly-conforming C.
Can you name any other functions in the standard C library which
cannot reasonably be written in strictly-conforming C, or does 2%
(3 out of about 150) constitute a "large fraction"?
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

torek@elf.ee.lbl.gov (Chris Torek) (04/21/91)

>lewine@cheshirecat.webo.dg.com (Donald Lewine) writes:
>>If there is [an ANSI C] library that is 60% ANSI conforming C,
>>you are doing very well.

In article <677@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>This is simply untrue.

Well, the percentage is off, but...

>We have a complete hosted ANSI C library written in ANSI C ...
>[with `about 10' system support calls].
>Considering there are over 150 functions in the library written in ANSI
>C, and less than a dozen tiny functions which are machine-specific, I'd
>say we do considerably better than 60%.

Just for comparison: the `free' BSD project has gotten fairly far along
in terms of the C library.  I ran the following commands:

	% tar cfFF - hp300 | wc
	    4640   31024  233472
	% tar cfFF - i386 | wc
	    2393   15243  122880
	% tar cfFF - vax | wc
	    5767   35098  253952
	% tar cfFF - tahoe | wc
	    6102   34337  253952
	% tar cfFF - db gen locale net stdio stdlib string sys | wc
	   85910  371098 2564096

(the undocumented capital-FF skips SCCS and RCS files).  This gives an
`overall' library ratio of about 5-to-10 percent machine dependent
code, depending on the machine (lower on the Intel-386, primarily due
to lack of tuning)---but this value is affected by several things:

 A. The library includes POSIX and BSD functions as well as `pure' ANSI
    C functions.

 B. There are `semiportable' versions of all of the string functions in
    the portable code, with CPU-specific versions in the machine
    directories.  Thus memcpy is counted once in `string' and once in
    `tahoe/string', for instance.

 C. The math library, which *should* be largely machine-dependent (for
    performance reasons), is not included above.  Adding them in:

	$ for i in [a-n]* tahoe vax
	> do
	> echo $i; tar cfFF - $i | wc; done
	common
	     780    4063   32768
	common_source
	    5927   29102  208896
	ieee
	     960    4608   36864
	mc68881
	    1433    8765   65536
	national
	     854    3972   24576
	tahoe
	     830    4792   32768
	vax
	    1951    9572   65536

    will require more analysis than I am willing to do here, because again
    there are many functions that have `semiportable' versions and rely on
    underlying pieces.

and of course

 D. `tar' throws the numbers off a bit.  (It was just a convenient way of
    not counting the revision control data.)
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

berg@marvin.e17.physik.tu-muenchen.de (Stephen R. van den Berg) (04/23/91)

Stephen Clamage writes:
>Can you name any other functions in the standard C library which
>cannot reasonably be written in strictly-conforming C, or does 2%
>(3 out of about 150) constitute a "large fraction"?

How about the declaration of the va_list macros.
--
Sincerely,                 berg@marvin.e17.physik.tu-muenchen.de
           Stephen R. van den Berg.
"I code it in 5 min, optimize it in 90 min, because it's so well optimized:
it runs in only 5 min.  Actually, most of the time I optimize programs."

ccplumb@rose.waterloo.edu (Colin Plumb) (04/26/91)

steve@taumet.com (Stephen Clamage) wrote:
>ccplumb@rose.waterloo.edu (Colin Plumb) writes:
>
>>- A large fraction of the ANSI C library can't be written in *strictly
>> conforming* ANSI C.
>
> In the full posting you mentioned only setjmp and longjmp...
> Can you name any other functions in the standard C library which
> cannot reasonably be written in strictly-conforming C, or does 2%
> (3 out of about 150) constitute a "large fraction"?

Okay, let me see...
First, I'll ignore the linker tricks used so library functions can call
other library functyions even without the proper incliude files
(e.g. assert() calls abort()).  I'll also assume that you don't want
a trivial library where everything hard returns failure (e.g. clock()).

Now, let's go through the header files:
errno.h - easy to write in C, assuming knowledge of the rest of the library
	(However, machine-dependent code may require machine-dependent errors)
float.h - not possible
limits.h - not possible
stddef.h - not possible (except for NULL)
assert.h - trivial
ctype.h - a basic implementation, with the "C" locale only and only
	characters from the C character set, is possible.
locale.h - no particular difficulty
math.h - since the standard imposes no accuracy constraints, and
	HUGE_VAL is obtainable from <float.h>, there is no difficulty
	in creating a minimal library.  Of course, it will be very
	low quality, and frexp/ldexp won't use the "obvious"
	implementation.
setjmp.h - not possible
signal.h - without external interrupts, a portable version can be written,
	except for SIG_DFL, SIG_ERR and SIG_IGN.  If you have external
	interrupts, this can't be written portably.
stdarg.h - not possible
stdio.h - large parts are writeable in C, although a number of #defines
	and typedefs can't be portably declared, and remove(), rename(),
	tmpnam(), fclose(), fopen(), some low-level read/write primitives
	(fread/fwrite, fgetc/fputc, or whatever), and some seek-type
	primitives are OS-dependent.
stdlib.h - A mixed bag.  As with <math.h>, a good strtod()
	isn't really possible, and malloc()/free() aren't portably
	writeable, nor is a realloc() that attempts to expand in place.
	exit(), of course, is non-portable, along with EXIT_FAILURE.
	getenv() isn't portable, and system() is the pits.  div() and
	ldiv() are here because they're uglay and inefficient in plain
	C, although writeable with the help of <limits.h>.  I'm not
	really sufficiently familiar with the multibyte stuff to see
	what interactions it has, although if you know the character
	sets, everything here is writeable in C.
string.h - memmove(), as I mentioned, is disgusting in strictly conforming C,
	and many of the other routines benefit greatly from low-level
	implmeementations, although there's no great loss from writing them
	in C.  strcoll() and strxfrm() depend on the locale stuff,
	if you're implementing non-C locales.  strerror() depends
	on any machine-dependencies in <errno.h>.
time.h - tm_isdst is difficult (assuming you don't punt), clock() and
	time() are, of course, non-portable, and the others all depend
	on time_t.  If you implement Unix-style unsigned long seconds
	since epoch, then everything else is portably writeable.

Does that give some idea of the size of the problem?  If you pick some
primitives to write it in terms of, you can write almost everything
in Strictly Conforming C, and a great deal more in semi-portable
C, but there are a lot of gtchas hiding in there.
-- 
	-Colin

jfc@athena.mit.edu (John F Carr) (04/26/91)

In article <1991Apr25.201855.27893@watdragon.waterloo.edu>
	ccplumb@rose.waterloo.edu (Colin Plumb) writes:
>signal.h - without external interrupts, a portable version can be written,
>	except for SIG_DFL, SIG_ERR and SIG_IGN.

You can declare functions and define the macros to be the addresses of
these functions (the function names need to be among those reserved to the
implementation, for example "__sig_dfl").  The address of a function is a
constant expression according to section 3.4 of the standard.

--
    John Carr (jfc@athena.mit.edu)

steve@taumet.com (Stephen Clamage) (04/26/91)

There have been a number of postings and some private mail regarding my
comments that almost all of the ANSI C library can be written in
strictly-conforming C.  Only three functions have been identified as not
possible to write -- setjmp, longjmp, and (being VERY strict) memmove.

The comments challenging my statement generally confound the concept of
"strictly conforming" with "completely portable".  The two concepts
are not the same.

Strictly-conforming C code may call an external function not supplied
with the translation unit:
	extern int foo(void);
	main() { return foo(); }
This is a strictly-conforming translation unit.  It is not portable to
systems which do not provide a function foo().  It might produce
different results on different systems, depending on what the local
version of foo() does.

The standard also does not state that foo() must be written in strictly-
conforming C for this unit to be strictly-conforming.  If I wrote foo()
in some odd dialect of C, does it affect the conformance of the
main() unit?  If it did, then no C program could ever be strictly-
conforming, since at some point buried in the library, some amount of
machine-dependence is required.  How does main get started?  How does a
hosted implementation accomplish file I/O?  We must conclude that things
outside the translation unit cannot affect how we evaluate conformance.

By extension, foo() need not be written in C at all, so long as it
provides an interface callable by a C program with C's function-call
semantics (the "as-if" rule).

If as an implementor, I provide (for example) a <limits.h> containing
the line
	#define INT_MAX 0x7FFFFFFF
this is strictly-conforming ANSI C.  This macro definition is not usable
on all systems, since not all systems use 32-bit integers.  If I provided
an implementation for a 16-bit system, I would use a different version of
<limits.h>.  Each implementation has a version of <limits.h> which is
correct for that system, but which need not be portable to other systems.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

gwyn@smoke.brl.mil (Doug Gwyn) (04/27/91)

In article <1991Apr25.201855.27893@watdragon.waterloo.edu> ccplumb@rose.waterloo.edu (Colin Plumb) writes:
>steve@taumet.com (Stephen Clamage) wrote:
>>ccplumb@rose.waterloo.edu (Colin Plumb) writes:
>>>- A large fraction of the ANSI C library can't be written in *strictly
>>> conforming* ANSI C.
>> In the full posting you mentioned only setjmp and longjmp...
>> Can you name any other functions in the standard C library ...
>First, I'll ignore the linker tricks used so library functions can call
>other library functyions even without the proper incliude files
>(e.g. assert() calls abort()).  I'll also assume that you don't want
>a trivial library where everything hard returns failure (e.g. clock()).

As a contributor to the (apparently now defunct) "DLIBS" project, and an
implementor of public-domain standard library functions, I've studied
this issue extensively and feel that some comments based on practical
experience would be useful.

There are no "linker tricks" required.  A strictly conforming program
need not include standard headers to access standard functions; it can
explicitly declare the ones it uses.

Most of the standard library functions are required to perform their
functions; certainly the majority should be implementable on all systems.

>float.h - not possible
>limits.h - not possible
>stddef.h - not possible (except for NULL)

All these CAN be written in a strictly conforming manner.
However, it may well be the case that no SINGLE definition of each
type or macro is UNIVERSAL.  Portability and strict conformance are
quite different properties.

I have, however, seen implementations of <limits.h> wherein the vast
majority of the definitions are also portable ones.

>stdio.h - large parts are writeable in C, although a number of #defines
>	and typedefs can't be portably declared, and remove(), rename(),
>	tmpnam(), fclose(), fopen(), some low-level read/write primitives
>	(fread/fwrite, fgetc/fputc, or whatever), and some seek-type
>	primitives are OS-dependent.

All of <stdio.h> can be implemented as strictly conformant AND portable;
however, one of course must assume the existence of a common set of low-
level IO functions such as __read() and use them in a minimally demanding
manner.

>Does that give some idea of the size of the problem?  If you pick some
>primitives to write it in terms of, you can write almost everything
>in Strictly Conforming C, and a great deal more in semi-portable
>C, but there are a lot of gtchas hiding in there.

Those points are correct, but note the shift from "strictly conforming"
to "completely portable".

P.J. Plauger's new book ("The Standard C Library", published by
Prentice-Hall "any day now") should provide concrete grounds for
further discussion of this issue.

bright@nazgul.UUCP (Walter Bright) (04/27/91)

In article <681@taumet.com> steve@taumet.com (Stephen Clamage) writes:
/In the full posting you mentioned only setjmp and longjmp as
/functions which cannot be written in strictly-conforming C, and
/memmove which cannot be written efficiently in strictly-conforming C.
/Can you name any other functions in the standard C library which
/cannot reasonably be written in strictly-conforming C.

Off the top of my head:
	malloc and friends, because implementation dependent details
	about pointer alignment need to be known.

	Any stdio functions, because they need to call operating system
	functions which aren't part of ANSI C.

	Any other functions which interface to the operating system,
	like time().

	Transcendental functions could be implemented, but would be
	inaccurate and slow if the mechanics of the underlying
	floating point were not taken advantage of.

	The startup code.

	The ctype.h functions, because they need to know if the
	implementation is ascii or some other scheme.

	The stdarg.h functionality.

gwyn@smoke.brl.mil (Doug Gwyn) (04/30/91)

In article <307@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
-In article <681@taumet.com> steve@taumet.com (Stephen Clamage) writes:
-/Can you name any other functions in the standard C library which
-/cannot reasonably be written in strictly-conforming C.
-	malloc and friends, because implementation dependent details
-	about pointer alignment need to be known.
-	Any stdio functions, because they need to call operating system
-	functions which aren't part of ANSI C.
-	Any other functions which interface to the operating system,
-	like time().
-	Transcendental functions could be implemented, but would be
-	inaccurate and slow if the mechanics of the underlying
-	floating point were not taken advantage of.
-	The startup code.
-	The ctype.h functions, because they need to know if the
-	implementation is ascii or some other scheme.
-	The stdarg.h functionality.

With the possible exception of the startup code, all the above can
be reasonably written in strictly-conforming C in most environments.

meranda@iguana.cis.ohio-state.edu (deron meranda) (05/01/91)

In article <695@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>There have been a number of postings and some private mail regarding my
>comments that almost all of the ANSI C library can be written in
>strictly-conforming C.  Only three functions have been identified as not
>possible to write -- setjmp, longjmp, and (being VERY strict) memmove.
>
>The comments challenging my statement generally confound the concept of
>"strictly conforming" with "completely portable".  The two concepts
>are not the same.
>
>Strictly-conforming C code may call an external function not supplied
>with the translation unit:
>...

This is all very true.  Most of the C library can indeed be written in
strictly-conforming C, although we may need to use external functions
to accomplish this.

However, perhaps a more informative question would be how much of the
C library can be written ENTIRELY in strictly conforming C without
the help of other external functions.  Again, however this is quite
different than the question of portability.

For example, consider the function strchr (section 4.11.5.2).  Clearly
if it were implemented entirely in C, it has to produce a plain char *
from a const char *.  Although most compilers will allow this with a
warning, it is not strictly-conforming C.

Understanding these kinds of problems are more important to me in
implementing the C library in C than realizing that some functions
require some external support.  So how does the library stand
against this criterion?


Deron E. Meranda  ( meranda@cis.ohio-state.edu )

henry@zoo.toronto.edu (Henry Spencer) (05/02/91)

In article <114913@tut.cis.ohio-state.edu> meranda@iguana.cis.ohio-state.edu (deron meranda) writes:
>For example, consider the function strchr (section 4.11.5.2).  Clearly
>if it were implemented entirely in C, it has to produce a plain char *
>from a const char *.  Although most compilers will allow this with a
>warning, it is not strictly-conforming C.

Uh, where did you get that idea?  Please cite chapter and verse.  Some
earlier drafts of ANSI C restricted pointer conversions so that this sort
of conversion was not strictly conforming; the result was loud protests
and the problem was fixed.

It is true that you have to beware of alignment in such conversions, but
that is not an issue here.  It is also true that if you use such a converted
pointer to attempt to modify a "const char" variable, all bets are off.  But
the conversion itself is strictly conforming.
-- 
And the bean-counter replied,           | Henry Spencer @ U of Toronto Zoology
"beans are more important".             |  henry@zoo.toronto.edu  utzoo!henry

joe@proto.com (Joe Huffman) (05/02/91)

gwyn@smoke.brl.mil (Doug Gwyn) writes:

>In article <307@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes:
>-In article <681@taumet.com> steve@taumet.com (Stephen Clamage) writes:
>-/Can you name any other functions in the standard C library which
>-/cannot reasonably be written in strictly-conforming C.
[...list deleted...]

>With the possible exception of the startup code, all the above can
>be reasonably written in strictly-conforming C in most environments.

Huh?  You have me a bit confused.  I did the port of Zortech to SCO UNIX.
How could have I written the following in 'C'?

_time   proc    near
        mov     eax,0dh         ;Get time from OS, result in EAX
       	db 9ah			; call far 0x7:0
	dd 0
	dw 07h

        mov     ecx,4[esp]      ;arg passed to time
        jecxz   short time_done ;== NULL?
        mov     [ecx],eax
time_done:
        ret
_time   endp


_lseek  proc    near
        mov     eax,19
       	db 9ah			; call far 0x7:0
	dd 0
	dw 07h
        jc      short cerror	; Carry set on error.
        ret
cerror:
        mov     _errno,eax      ; errno = value returned by kernel
        sbb     eax,eax         ; return value = -1
        ret

_lseek  endp

Note that values must be put in a specific register (EAX) before doing a 
"far" call.  ANSI doesn't recognize a 'far' or 'near' call and in this
implementation of UNIX all 'normal' functions calls are near calls.  Yet to
'talk' to the OS you must go through a 'far' call.  Note also that the 
'Carry' flag is set on error.  Also note that in the case of lseek (required
to implement fseek()) arguments are passed on the stack frame of the caller.
lseek() cannot have it's own stack frame.

So... just one of the many questions that could be asked having gone through
this exercise...  How do I get the carry flag status on return from a 
function call that I can't make, having passed parameters in registers I 
can't access from an ANSI conforming program?

Surely I have missed an assumption you made someplace... this doesn't qualify
as 'most enviroments'?  Yet all other environments that I am familar with 
differ only in the details.
-- 
joe@proto.com

meranda@iguana.cis.ohio-state.edu (deron meranda) (05/03/91)

Concerning strchr() and const char *'s...

In article <1991May1.170750.19222@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
>In article <114913@tut.cis.ohio-state.edu> meranda@iguana.cis.ohio-state.edu I write:
>>For example, consider the function strchr (section 4.11.5.2).  Clearly
>>if it were implemented entirely in C, it has to produce a plain char *
>>from a const char *.  Although most compilers will allow this with a
>>warning, it is not strictly-conforming C.
>
>Uh, where did you get that idea?  Please cite chapter and verse.  Some
>earlier drafts of ANSI C restricted pointer conversions so that this sort
>of conversion was not strictly conforming; the result was loud protests
>and the problem was fixed.
>
>It is true that you have to beware of alignment in such conversions, but
>that is not an issue here.  It is also true that if you use such a converted
>pointer to attempt to modify a "const char" variable, all bets are off.  But
>the conversion itself is strictly conforming.

It appears as if you are correct.  The Rationale 3.3.4 clearly
states that a (const char *) may be typecast to a (char *).
However, it also appears that one can not even dereference the
resulting pointer, whether or not the object is modified
(actually the behavior is undefined).  Furthermore, as you note,
alignment is no problem, not only because we are dealing with
chars, but also because qualifiers make no difference in
alignment (3.1.2.5 p25 line22).

I was confused because section 3.2.2.3 states that a plain
char * may be "automatically" converted into a const char *.
On the contrary, the Rationale 3.1.4 makes a quick statement
that the assignment of a const char * to a plain char * is
illegal.  However, (misunderstood by me) both of these
statements are within the context of having no explicit type
casts present.


Now, back to the question about implementing strchr() entirely
in strictly conforming C.  If it is not possible to convert a
const char * to a plain char *, without loosing to ability to
dereference the resulting pointer (without a cast), then at
best, strchr() can only return a pointer which can not be
directly dereferenced.

From this, it then appears to me that the following program
segment becomes illegal (or at least undefined):

   char Array [5] = { 'a', 'b', 'c', 'd', '\0' };
   char * c;

   c = strchr( Array, 'd' );
   if( c ) printf("character is %c", *c );

Clearly this should be legal under a conforming implementation
of strchr().  Therefore, am I correct in saying that strchr
can not correctly be written entirely in strictly conforming C?
I confess, that this should work on almost every possible
implementation environment, but the behavior is still undefined
as far as the standard goes --- if you follow the rules!

I would appreciate anyone's comments on this.  This behavior
seems awfully strange to me, and I am probably misreading
something rather obvious.  Even if the above was well-defined,
the mechanism is at best rather barbaric.


Deron E. Meranda  ( meranda@cis.ohio-state.edu )

gwyn@smoke.brl.mil (Doug Gwyn) (05/04/91)

In article <116105@tut.cis.ohio-state.edu> meranda@iguana.cis.ohio-state.edu (deron meranda) writes:
>Concerning strchr() and const char *'s...
>It appears as if you are correct.  The Rationale 3.3.4 clearly
>states that a (const char *) may be typecast to a (char *).
>However, it also appears that one can not even dereference the
>resulting pointer, whether or not the object is modified
>(actually the behavior is undefined).

As I recall the constraints, you can certainly access the pointer-to
object for reading, and unless the actual object itself is const-
qualified, you can also access it for writing.  The "const" in a
"const char *" parameter does NOT mean that the pointed-to chars
have to be read-only; rather, it means that the function cannot use
that parameter to modify them.

I see no problem in implementing strchr() using strictly conforming code:

char *strchr( const char *s, int c )
	{
	do
		if ( *s == (char)c )
			return (char *)s;
	while ( *s++ != '\0' );

	return (char *)0;
	}

gwyn@smoke.brl.mil (Doug Gwyn) (05/04/91)

In article <16053@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>you can certainly access the pointer-to object for reading, and ...

That was meant to be "pointed-to object".

steve@taumet.com (Stephen Clamage) (05/05/91)

meranda@iguana.cis.ohio-state.edu (deron meranda) writes:

>Now, back to the question about implementing strchr() entirely
>in strictly conforming C.  If it is not possible to convert a
>const char * to a plain char *, without loosing to ability to
>dereference the resulting pointer (without a cast), then at
>best, strchr() can only return a pointer which can not be
>directly dereferenced.

You can dereference the pointer.  It is just that the result of
attempting to assign to a const object is undefined.  It is perfectly
legal to cast back and forth between 'T*' and 'const T*', so long as you
bear this in mind.

>From this, it then appears to me that the following program
>segment becomes illegal (or at least undefined):
>   char Array [5] = { 'a', 'b', 'c', 'd', '\0' };
>   char * c;
>   c = strchr( Array, 'd' );
>   if( c ) printf("character is %c", *c );
>Clearly this should be legal under a conforming implementation

And so it is.  You are nowhere assigning through a pointer to const.

>Therefore, am I correct in saying that strchr
>can not correctly be written entirely in strictly conforming C?

No, there is no problem with writing strchr in strictly conforming C.
All of the casting and dereferencing within strchr is perfectly ok.
If you in fact pass strchr a const string and attempt to assign
through the returned pointer, the result is undefined.

char *p;	/* pointer to non-const */
const char *pc;	/* pointer to const */

char *s = strchr(p, 'a');	/* ok */
char *t = strchr(pc, 'a');	/* ok */
*s = 'A';			/* ok -- s points to a non-const char */
*t = 'A';			/* not strictly conforming */

The last line above is in general not detectable by a compiler as not
strictly conforming (the effect might be spread across several compilation
units).  The effect of assigning to what 't' points to (some place in
what 'pc' points to) is undefined.  In fact, 'pc' might point to a
non-const string and this is really ok.  We can only know, however, that
what 'pc' points to is not supposed to be modified.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com