[comp.lang.c] Some Comments & Questions about ANSI C

geoff@cs.warwick.ac.uk (Geoff Rimmer) (06/12/89)

1. 15 standard include files are listed in K&R2.  Only 12 are
described in sufficient detail.  The other three are

	errno.h	 - this will contain the #defines for error messages.
		   But will it contain the declaration "extern int errno" ?
	locale.h - This will contain "properties that depend on local
		   language, nationality, or culture".  Such as?
	stddef.h - Definition of the type size_t (A7.4.8).  But what
		   else goes in here?  ino_t and dev_t presumably stay
		   in sys/types.h (8.6 p 181).

2. It seems to me that every time I want to #include <stdio.h>, I must
also #include <stdarg.h> and <stddef.h> beforehand.  This is to stop
it barfing on the function declarations in <stdio.h> like

	size_t fread( void *, size_t, size_t, FILE * );
		/* size_t is defined in <stddef.h> */

and
	int vprintf( const char *, va_list );
		/* va_list is defined in <stdarg.h> */

I find this annoying sometimes, especially when working on a simple
program that is only including <stdio.h> to get _iobuf defined.  Am I
correct on this?

3. Am I missing something, or is "difftime" the most simple function
around?  It seems to me that it is essentially a subtract:

	double difftime( time_t t2, time_t t1)
	{
		return (double)t2 - t1;
	}
In which case, why is it a function?  I'd rather do a subtraction myself!

4. I'm still not entirely sure I understand "void *".  If I have a
function which takes as argument a void *, and I want to pass it the
variable x (which could be of type char *, int *, or even
float(*)(int,char*) ), do I have to CAST x to a (void *) when calling
the function?  Similarly, if the function then returned a void *, and
I have a variable y of type int *, would I have to do
	y = (int *) function (......);
?

5. Does the standard say anything about where function definitions for
fopen and opendir must go?  Also, is <dirent.h> mentioned in the
standard, or is it up to the individual implementor to choose this?

6. Finally, I see there's no strdup in ANSI C.  Sigh.  I guess it's
back to 

	#define strdup(x) (strcpy(Malloc(strlen(x)+1),(x)))

	:-(

Geoff
	One of these days, I'm going to write an ANSI C compiler.  And
	whenever it encounters some code whose behavior is undefined
	(such as fflush(stdin);) it will draw a picture of Snow White (tm) 
	on the screen, and then play Rule Brittania 3 times, before
	crashing with a segmentation fault, and leaving a
		while(1){fork();malloc(UINT_MAX);}
	running in the background. 

	/---------------------------------------------------------------\
	|	GEOFF RIMMER						|
	|	email	: geoff@uk.ac.warwick.cs			|
	|	address : Computer Science Dept, Warwick University, 	|
	|		  Coventry, England.				|
	|	PHONE	: +44 203 692320				|
	|	FAX	: +44 865 726753				|
	\---------------------------------------------------------------/

"No representation without taxation!"
	- Rik Mayall, The New Statesman.

karl@haddock.ima.isc.com (Karl Heuer) (06/13/89)

In article <GEOFF.89Jun11231924@onyx.cs.warwick.ac.uk> geoff@cs.warwick.ac.uk (Geoff Rimmer) writes:
>1. 15 standard include files are listed in K&R2.  Only 12 are
>described in sufficient detail.

The remaining details are in the Standard itself.

>	errno.h	 - this will contain the #defines for error messages.
>		   But will it contain the declaration "extern int errno" ?

It will declare errno, though perhaps not with that declaration.  (In a
multi-threaded environment, something like "#define errno (*__errno())" may be
necessary.)

>	locale.h - This will contain "properties that depend on local
>		   language, nationality, or culture".  Such as?

The type "struct lconv", whose members describe such things as the format for
what would be "$15,742.18" in the USA; the function localeconv(), which
returns a pointer to such a (filled-in) struct; the function setlocale(),
which allows the application to specify which locale is to be used; and a
bunch of macros LC_*, which are used to specify to setlocale() which features
are to be changed (character collation, ctype, monetary format, decimal-point
character, strftime() %x/%X format).

>	stddef.h - Definition of the type size_t (A7.4.8).  But what
>		   else goes in here?  ino_t and dev_t presumably stay
>		   in sys/types.h (8.6 p 181).

Yes (though <sys/types.h> is part of POSIX, not ANSI C).  The other things
defined in <stddef.h> are ptrdiff_t and wchar_t, and the offsetof() macro, and
NULL (which is also defined elsewhere).

>2. It seems to me that every time I want to #include <stdio.h>, I must
>also #include <stdarg.h> and <stddef.h> beforehand.

No.  Any implementation that requires this is broken.

>This is to stop it barfing on the function declarations in <stdio.h> like
>	size_t fread( void *, size_t, size_t, FILE * );
>		/* size_t is defined in <stddef.h> */

The type size_t is defined in both <stdio.h> and <stddef.h> (and elsewhere).
(This requires its definition to be enclosed in an idempotency guard$, alas.)

>	int vprintf( const char *, va_list );
>		/* va_list is defined in <stdarg.h> */

This one is annoying (to the implementor); it seems that the correct way to do
this is to declare vprintf() using the expansion of va_list rather than the
typedef itself.

>3. Am I missing something, or is "difftime" the most simple function
>around?  It seems to me that it is essentially a subtract:

This is true on a POSIX system, where time_t is required to be measure in
seconds since the Epoch.  Other ANSI C implementations might encode the time
as YYMMDDHHMMSS in decimal, or something; in this case difftime() would be
nontrivial.

>4. ... do I have to CAST [the arguments and/or the return value of a function
>that expects and/or returns (void *)]?

An implicit conversion will be done; at worst, this will be a warning.

>5. Does the standard say anything about where function definitions for
>fopen and opendir must go?  Also, is <dirent.h> mentioned in the
>standard, or is it up to the individual implementor to choose this?

fopen() goes in <stdio.h>.  opendir() isn't an ANSI C function; POSIX puts it
in <dirent.h>, which header is likewise not part of ANSI C.

>6. Finally, I see there's no strdup in ANSI C.  Sigh.

There's no read() in ANSI C either, but I doubt I'll ever encounter an
implementation that doesn't have it.  My solution for strdup() is to keep a
copy in my private library on any implementation that doesn't have one in the
standard place.%

>Geoff
>	One of these days, I'm going to write an ANSI C compiler.  And
>	whenever it encounters some code whose behavior is undefined
>	(such as fflush(stdin);) it will draw a picture of Snow White (tm)
>	on the screen, and then play Rule Brittania 3 times, before
>	crashing with a segmentation fault, and leaving a
>		while(1){fork();malloc(UINT_MAX);}
>	running in the background.

Quality of Implementation issues are usually resolved by the free market.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
Followups to comp.std.c only.
________
$ A definition is idempotent if executing it twice yields the same result as
  executing it once.  Since this is not automatically true for typedefs, any
  that have more than one home have to be guarded with something like
	#if !defined(_T_SIZE)
	#define _T_SIZE
	typedef unsigned int size_t;
	#endif
% Technically this is illegal because the str* namespace is reserved, and
  hence a convoluted implementation could use the name "strdup" for something
  other than the obvious; but somehow I'm not worried about this.

dfp@cbnewsl.ATT.COM (david.f.prosser) (06/13/89)

In article <GEOFF.89Jun11231924@onyx.cs.warwick.ac.uk> geoff@cs.warwick.ac.uk (Geoff Rimmer) writes:
>
>1. 15 standard include files are listed in K&R2.  Only 12 are
>described in sufficient detail.  The other three are
>
>	errno.h	 - this will contain the #defines for error messages.
>		   But will it contain the declaration "extern int errno" ?

Yes, or its equivalent.

>	locale.h - This will contain "properties that depend on local
>		   language, nationality, or culture".  Such as?

Mostly, it contains the declaration of the lconv structure (with 18
or so members), some macros that begin with LC_, and the declarations
of setlocale() and localeconv().

>	stddef.h - Definition of the type size_t (A7.4.8).  But what
>		   else goes in here?  ino_t and dev_t presumably stay
>		   in sys/types.h (8.6 p 181).

It (only) contains the typedefs for ptrdiff_t, size_t, and wchar_t, and
the macros NULL and offsetof().

>
>2. It seems to me that every time I want to #include <stdio.h>, I must
>also #include <stdarg.h> and <stddef.h> beforehand.  This is to stop
>it barfing on the function declarations in <stdio.h> like
>
	[example deleted]
>
>I find this annoying sometimes, especially when working on a simple
>program that is only including <stdio.h> to get _iobuf defined.  Am I
>correct on this?

No.  An ANSI C conforming version of <stdio.h> must not require the
preinclusion of any other headers; nor can it have any other ordering
dependency with respect to any other standard header.  Moreover, after
including <stdio.h>, size_t should be typedef'd and va_list should be
undefined (assuming no other headers have been included).

>
>3. Am I missing something, or is "difftime" the most simple function
>around?  It seems to me that it is essentially a subtract:
>
>	double difftime( time_t t2, time_t t1)
>	{
>		return (double)t2 - t1;
>	}
>In which case, why is it a function?  I'd rather do a subtraction myself!

This presupposes that time_t is a simple numeric representation.  On some
systems, the dates are kept as bit fields within an arithmetic type.

>
>4. I'm still not entirely sure I understand "void *".  If I have a
>function which takes as argument a void *, and I want to pass it the
>variable x (which could be of type char *, int *, or even
>float(*)(int,char*) ), do I have to CAST x to a (void *) when calling
>the function?  Similarly, if the function then returned a void *, and
>I have a variable y of type int *, would I have to do
>	y = (int *) function (......);
>?

First, let's assume that you have a prototype for the function in scope at
the call.  Then, the argument expression is handled as if it were assigned
to an object of type void *: any pointer to an object is automatically
converted to void * for you, unless the type pointed to has more qualifiers
(const and volatile) than the void in the void * target.  Note that your
last example [float (*)(int, char *)] is a pointer to a function and as such,
cannot be (portably) assigned to a void * (with or without an implicit cast).

If there is no prototype in scope for the function at the call, you are
responsible for converting any mismatched types (after application of the
default argument promotions).

The rules when assigning from a void * are symmetric: a void * will be
automatically converted to any other pointer to object type, as long as no
qualifiers (on the pointed to type) are lost in the conversion.

>
>5. Does the standard say anything about where function definitions for
>fopen and opendir must go?  Also, is <dirent.h> mentioned in the
>standard, or is it up to the individual implementor to choose this?

fopen() is declared in <stdio.h>.  ANSI C knows nothing about <dirent.h>
and opendir(), but both of these are required (as I understand it) by
POSIX 1003.1.

>
>6. Finally, I see there's no strdup in ANSI C.  Sigh.  I guess it's
>back to 
>
>	#define strdup(x) (strcpy(Malloc(strlen(x)+1),(x)))
>
>	:-(

If you desire.  However, such a macro will render your program as
not strictly conforming if <string.h> has been included in the same
compilation.  Try "mystrdup" instead.  Personally, I prefer my own
function that doesn't allow for a NULL return...that's why I don't
really use strdup(), anyway.

>
>Geoff

Dave Prosser	--not an official statement from X3J11--

rex@aussie.UUCP (Rex Jaeschke) (06/13/89)

> 	errno.h	 - this will contain the #defines for error messages.
> 		   But will it contain the declaration "extern int errno" ?

Yes. This is the ONLY place errno should be declared. Not in math.h and 
not in stddef.h (where it lived until errno.h was created.)

> 	locale.h - This will contain "properties that depend on local
> 		   language, nationality, or culture".  Such as?

Prototypes for setlocale and localeconv functions, macro 
definitions for the LC_* family and the lconv structure template for 
all the currency info. This struct and the set of LC_* macros can be 
extended by the implementer.

> 	stddef.h - Definition of the type size_t (A7.4.8).  But what
> 		   else goes in here?  ino_t and dev_t presumably stay
> 		   in sys/types.h (8.6 p 181).

typedefs: size_t, ptrdiff_t, wchar_t
macros: NULL, offsetof
That's all.

> 2. It seems to me that every time I want to #include <stdio.h>, I must
> also #include <stdarg.h> and <stddef.h> beforehand.

Each and every std header must be self-sufficient and MUST NOT 
#include any other std header. A common practice is/was to define 
va_end as ap = NULL. No can do 'cos NULL isn't defined in stdarg.h.

> 4. I'm still not entirely sure I understand "void *".  If I have a

A void pointer is assignment compatible with all "real" pointers and 
needs no explicit cast in assignment, passing arguments in, or getting 
values back from functions.

> 5. Does the standard say anything about where function definitions for
> fopen and opendir must go?  Also, is <dirent.h> mentioned in the
> standard, or is it up to the individual implementor to choose this?

fopen is stdio.h; opendir and direct.h non-std.

> 6. Finally, I see there's no strdup in ANSI C.  Sigh.  I guess it's

Correct.

Rex

----------------------------------------------------------------------------
Rex Jaeschke     | C Users Journal     |  Journal of C Language Translation
(703) 860-0091   | DEC PROFESSIONAL    |1810 Michael Faraday Drive, Suite 101
uunet!aussie!rex | Programmers Journal |     Reston, Virginia 22090, USA
----------------------------------------------------------------------------
Convener of the Numerical C Extensions Group (NCEG)
----------------------------------------------------------------------------

peter@ficc.uu.net (Peter da Silva) (06/13/89)

In article <GEOFF.89Jun11231924@onyx.cs.warwick.ac.uk>, geoff@cs.warwick.ac.uk (Geoff Rimmer) writes:
> 3. Am I missing something, or is "difftime" the most simple function
> around?  It seems to me that it is essentially a subtract.

time_t doesn't have to be an integer count of seconds. In fact, on MS-DOS
machines time_t looks pretty much like this:

Bits:	    15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
Low word:  |    HOURS          |    MINUTES            |    SECONDS/2     |
High word: |      YEARS-1980       |   MONTHS          |    DAYS          |

On AmigaDOS, it's three words containing days in the epoch, minutes, and
ticks (50 ticks to a second), though most compilers turn this into a UNIX
style second count if you use a UNIX-style library call.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.

Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.
Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.