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