[net.lang.c] ANSI 'C'.

peter@graffiti.UUCP (Peter da Silva) (11/18/85)

I finally got hold of a copy of the new proposed standard (thanks Stanley!),
and would like to point out a problem with it: it's a prescriptive rather
than a descriptive standard. Now I know ANSI has acquired a habit of making
prescriptive standards lately, but at least there had been a pre-existing
descriptive standard to work from. Oh well.

I would also like to point out that there are several UNIX-like functions in
the library that are inappropriate for most non-UNIX implementations of 'C'.
In particular, the time functions (ctime(3) in the UPM) are unimplementable
in many systems, due to the lack of a daylight savings flag in the O/S. Would
it be acceptable to seperate O/S and language library functions so that non
UNIX environments can support ANSI-C?

Finally, if \v is to produce a vertical tab, does that require the I/O library
to include termcap so that the various output devices that implement this
function in various ways can be accomodated?

Basically, the standard is far too specific... it prescribes actions that are
strictly outside the definition of the language.
-- 
Name: Peter da Silva
Graphic: `-_-'
UUCP: ...!shell!{graffiti,baylor}!peter
IAEF: ...!kitty!baylor!peter

ron@brl-sem.ARPA (Ron Natalie <ron>) (11/18/85)

> I finally got hold of a copy of the new proposed standard (thanks Stanley!),
> and would like to point out a problem with it: it's a prescriptive rather
> than a descriptive standard. Now I know ANSI has acquired a habit of making
> prescriptive standards lately, but at least there had been a pre-existing
> descriptive standard to work from. Oh well.

Crapola, ANSI standards are almost always based on some existing work.  But
anything that's done by committee is likely to get riddled with a lot of
self interests.

> I would also like to point out that there are several UNIX-like functions in
> the library that are inappropriate for most non-UNIX implementations of 'C'.
> In particular, the time functions (ctime(3) in the UPM) are unimplementable
> in many systems, due to the lack of a daylight savings flag in the O/S. Would
> it be acceptable to seperate O/S and language library functions so that non
> UNIX environments can support ANSI-C?

Eh?  The timezone never belonged in the operating system!  Unix time is GMT.
Most versions of UNIX these days use an environment variable to convey
timezone information to the user process.  All the C environment needs to
know is how to convert from GMT and LOCAL time to whatever the system uses
for time and back.  If you can't do this, it's likely to be impossible to
use times in C at all, regardless of how CTIME is specified.

> 
> Finally, if \v is to produce a vertical tab, does that require the I/O library
> to include termcap so that the various output devices that implement this
> function in various ways can be accomodated?

Vertical TAB is an ASCII character.  If the terminal doesn't support it,
who cares.  Some terminals don't do horizontal tab either, you want to
pull \t?  My model37 won't do \r either.

-Ron

atbowler@watmath.UUCP (Alan T. Bowler [SDG]) (11/20/85)

In article <538@brl-sem.ARPA> ron@brl-sem.ARPA (Ron Natalie <ron>) writes:
>
>Eh?  The timezone never belonged in the operating system!  Unix time is GMT.
>Most versions of UNIX these days use an environment variable to convey
>timezone information to the user process.  All the C environment needs to
>know is how to convert from GMT and LOCAL time to whatever the system uses
>for time and back.  If you can't do this, it's likely to be impossible to
>use times in C at all, regardless of how CTIME is specified.
>
The original problem still stands.  The ANSI standard is specifying that
a library function be able to produce a value that is not available on
a large number of systems.  No one really questions that Unix was right
in deciding to store system time in GMT and make available information
to compute some appropriate "local" time from GMT data.  However,
believe it or not there are non-Unix environments out there.  No matter
what the standard says, many operating systems do not have environment
variables, and many of them do not keep time as GMT.  The only time
function supplied by the operating system effectively returns the value on
the wall clock beside the operator's console.  There is no available hint
about the relation between this, and GMT or whether it is daylight
savings time or not.
  The standard has no real business specifying the environment in this
amount of detail, or perhaps it should be worded with something like
"If you are going to supply XXXX functionality, do it like this...".

  I can live with the GETENV description since nothing stops me from
just defining a GETENV that always returns NULL.  I can't really live
with the requirement that I supply routines LOCALTIME, and GMTIME
since both require me to return information that is not available to me.

rbutterworth@watmath.UUCP (Ray Butterworth) (11/20/85)

>   The standard has no real business specifying the environment in this
> amount of detail, or perhaps it should be worded with something like
> "If you are going to supply XXXX functionality, do it like this...".

The standard obviously didn't put much thought into anything related to
times.  They define type "time_t" as an arithmetic type that represents
the time, and then define a difftime(time_t time1,time_t time2) that
computes the difference between these two arithmetic values.  Why the
function?  Does the standard have a new arithmetic type on which the
operation of subtraction is not allowed?
And then they define a function gmtime(const time_t *timer) that takes
a pointer to the arithmetic value, which it is not going to change anyway.
Why not just take the value itself instead of the pointer?

peter@graffiti.UUCP (Peter da Silva) (11/21/85)

> Crapola, ANSI standards are almost always based on some existing work.  But
> anything that's done by committee is likely to get riddled with a lot of
> self interests.

And you don't see this as a problem?

> > in many systems, due to the lack of a daylight savings flag in the O/S. Would

> Eh?  The timezone never belonged in the operating system!  Unix time is GMT.

Ctime(3) includes the definition of struct tm. This has been included bodily
in the X3J11 library. The structure includes an element "tm_isdst", which is
true if daylight savings time is currently active. This does NOT belong in
a language standard.

> > Finally, if \v is to produce a vertical tab, does that require the I/O library
> > to include termcap so that the various output devices that implement this
> > function in various ways can be accomodated?
> 
> Vertical TAB is an ASCII character.  If the terminal doesn't support it,

The definition of the 'C' character set doesn't mention ASCII. It merely says
that '\v' should advance to the next vertical tab mark. Immediately before this
there are included a whole series of escape sequences that seem adequate to
write 'C' programs in CDC 64-character code. At the very least the language
is clumsy.
-- 
Name: Peter da Silva
Graphic: `-_-'
UUCP: ...!shell!{graffiti,baylor}!peter
IAEF: ...!kitty!baylor!peter

lr@sftig.UUCP (L.Rosler) (11/21/85)

> >   The standard has no real business specifying the environment in this
> > amount of detail, or perhaps it should be worded with something like
> > "If you are going to supply XXXX functionality, do it like this...".
> 
> The standard obviously didn't put much thought into anything related to
> times.  They define type "time_t" as an arithmetic type that represents
> the time, and then define a difftime(time_t time1,time_t time2) that
> computes the difference between these two arithmetic values.  Why the
> function?  Does the standard have a new arithmetic type on which the
> operation of subtraction is not allowed?
> And then they define a function gmtime(const time_t *timer) that takes
> a pointer to the arithmetic value, which it is not going to change anyway.
> Why not just take the value itself instead of the pointer?

Several members of the X3J11 Committee are working on a rationale
document that will, I hope, clarify some apparently obscure choices.
It happens that a great deal of thought went into every aspect of
this issue.

The first question was whether methods of determining and reporting
time belonged in the C standard at all, or were properly part of a
system-interface standard such as that being produced by IEEE P1003
(nee /usr/group).  It was decided that the functionality desired
was sufficiently widely available to warrant standardization in the
language.  Provisions were made for environments that didn't have
the capability, by specifying a suitable error return which the
application could check for (the same value as that used by UNIX*,
not by coincidence).

The second question, the need for inventing difftime(), was based
on the concept that though the value returned by time() had to be
arithmetic (in order that the error value, (time_t)-1, be easily
detected), there was no need to burden implementations by requiring
it to be a linear representation of the time, as it happens to be
on UNIX systems.  It need not even be monotonically increasing,
viewed as an integer!  The question of appropriate units for the
difference of two times was finessed by specifying the result of
the subtraction as a double, catering for resolutions of integer
seconds on slow systems or nanoseconds on CRAYs.

The third question, why accept a pointer argument instead of the
value itself, reflects the encrustation of UNIX archaisms on a
standard of this kind.  In olden times, before C even had a "long"
data type, the time was stored in an array of two 16-bit ints,
hence HAD to be moved around via a pointer.  (Remember that the
name of the array serves as a pointer to the first element.)
This is why time_t time(time_t *timer) can return a value via
a side-effect on an argument.  As a C function cannot return an
array, originally this was the ONLY way time() could produce a
result.  When "long" was introduced, old programs continued to
operate through the type mismatch, provided the order of the
int's in the array was suitable to produce a "long".  The
time() function thus acquired a legitimate return value, and
the side-effect was conserved for compatibility.

No one on the Committee is PROUD of this kind of specification,
nor would we design such functions that way ab initio.  But one
of the roles of rational standardization is to preserve what is,
not create what should be.

Thanks for your indulgence.  We really do think hard on
occasion.

Larry Rosler, AT&T
Editor, X3J11 C Standards Committee
(201) 522-5086

* UNIX is a trademark of AT&T.

ark@alice.UucP (Andrew Koenig) (11/21/85)

> The standard obviously didn't put much thought into anything related to
> times.  They define type "time_t" as an arithmetic type that represents
> the time, and then define a difftime(time_t time1,time_t time2) that
> computes the difference between these two arithmetic values.  Why the
> function?  Does the standard have a new arithmetic type on which the
> operation of subtraction is not allowed?
> And then they define a function gmtime(const time_t *timer) that takes
> a pointer to the arithmetic value, which it is not going to change anyway.
> Why not just take the value itself instead of the pointer?

gmtime takes a pointer rather than the value itself for historical
reasons.  Before C had long integers, gmtime() took an array of
two integers as its argument.  Since C does not pass arrays by value,
gmtime() actually saw a pointer.

lr@sftig.UUCP (L.Rosler) (11/22/85)

> In article <538@brl-sem.ARPA> ron@brl-sem.ARPA (Ron Natalie <ron>) writes:
> >
> >Eh?  The timezone never belonged in the operating system!  Unix time is GMT.
> >Most versions of UNIX these days use an environment variable to convey
> >timezone information to the user process.  All the C environment needs to
> >know is how to convert from GMT and LOCAL time to whatever the system uses
> >for time and back.  If you can't do this, it's likely to be impossible to
> >use times in C at all, regardless of how CTIME is specified.
> >
> The original problem still stands.  The ANSI standard is specifying that
> a library function be able to produce a value that is not available on
> a large number of systems.  No one really questions that Unix was right
> in deciding to store system time in GMT and make available information
> to compute some appropriate "local" time from GMT data.  However,
> believe it or not there are non-Unix environments out there.  No matter
> what the standard says, many operating systems do not have environment
> variables, and many of them do not keep time as GMT.  The only time
> function supplied by the operating system effectively returns the value on
> the wall clock beside the operator's console.  There is no available hint
> about the relation between this, and GMT or whether it is daylight
> savings time or not.
>   The standard has no real business specifying the environment in this
> amount of detail, or perhaps it should be worded with something like
> "If you are going to supply XXXX functionality, do it like this...".

Perhaps it is unrealistic to expect people who state what the "ANSI
standard is specifying" to have read it.  The draft actually says,
"The gmtime function returns ... a null pointer if GMT is not available."
The presumption is that if the time() function works at all (see my
previous posting on THAT subject), then it is reasonable to expect
localtime() to work also.  If gmtime() is available, it must work
as specified; otherwise it fails in a specified way.  In other words,
"If you are going to supply gmtime functionality, do it like this...".

>   I can live with the GETENV description since nothing stops me from
> just defining a GETENV that always returns NULL.  I can't really live
> with the requirement that I supply routines LOCALTIME, and GMTIME
> since both require me to return information that is not available to me.

But they don't.

Larry Rosler, AT&T
Editor, X3J11 C Standards Committee
(201) 522-5086

seifert@hammer.UUCP (Snoopy) (11/22/85)

In article <170@watmath.UUCP> atbowler@watmath.UUCP (Alan T. Bowler [SDG]) writes:
>In article <538@brl-sem.ARPA> ron@brl-sem.ARPA (Ron Natalie <ron>) writes:
>>
>>Eh?  The timezone never belonged in the operating system!  Unix time is GMT.
>>Most versions of UNIX these days use an environment variable to convey
>>timezone information to the user process.  All the C environment needs to
>>know is how to convert from GMT and LOCAL time to whatever the system uses
>>for time and back.  If you can't do this, it's likely to be impossible to
>>use times in C at all, regardless of how CTIME is specified.

System V uses $TZ to get timezone information, so each user can have their
own timezone.  (one point for sysV) But there doesn't seem to be anyway
to get other than USA style daylight savings time unless you have
source and can hack ctime.c, where the daylight time stuff is hardcoded
in. (minus 'n' points for sysV unless you live in the US)

4.2 has provisions for different types of daylight savings time,
which can be changed via settimeofday(2).  (The tables for
european daylight time are wrong, but better than nothing)
4.3 fixes (I think) the tables for europe, and adds one for
Canada, which was different than the US in '74 and '75.
(Like, who cares *now* ?)

I've modified date(1) for Utek 2.2, adding -z and -d options,
to set the timezone and type of daylight savings time.  I'm
thinking about teaching localtime(3) about $TZ, so that you
could type:  "TZ=some_other_zone date" and get the time for
some other timezone easily.  (e.g. to see if it's a good time
to call someone.)  comments?

>  The ANSI standard is specifying that
>a library function be able to produce a value that is not available on
>a large number of systems.   ...   The only time
>function supplied by the operating system effectively returns the value on
>the wall clock beside the operator's console.  There is no available hint
>about the relation between this, and GMT or whether it is daylight
>savings time or not.
>  ...
>  I can live with the GETENV description since nothing stops me from
>just defining a GETENV that always returns NULL.  I can't really live
>with the requirement that I supply routines LOCALTIME, and GMTIME
>since both require me to return information that is not available to me.

Let's be careful before we start throwing things away just because
some other system can't support it.  We can't make C fit the lowest
common denominator, because that's pretty low.   Throw away time
functions because the Fubar 2000 running SNAFUDOS can't support them,
and throw away floating point because the Whatiz 907 can't support it,
and throw away upper/lower case because...  (you get the idea)

Snoopy (ECS Ronin #901)
tektronix!tekecs!doghouse.TEK!snoopy

henry@utzoo.UUCP (Henry Spencer) (11/23/85)

> And then they define a function gmtime(const time_t *timer) that takes
> a pointer to the arithmetic value, which it is not going to change anyway.
> Why not just take the value itself instead of the pointer?

*That* one, at least, is easy to explain:  because that is the way the
Unix function does it, for historical reasons, and nobody wants to break
all that working code.

As for why the Unix function does it that way...  gmtime() predates the
arrival of "long" in C.  Back In The Bad Old Days, with no type "long",
32-bit values had to be manipulated as small arrays of int.  There were
functions to add them, etc.  Note that one can pass the address of an
array but not the array itself.  And that's why virtually all Unix library
functions that deal with time take pointers to time_t rather than just
time_t.  (If you want a really odd example, look at the time(2) manual
page -- it has two different ways to return its value!)

Oh yes, a word to the careless (and to Laura for her book):  one should
not assume that time_t and long are the same type.  Sometimes they're not,
old (e.g. V7) or broken (e.g. 4.2BSD) manuals notwithstanding.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

ron@brl-sem.ARPA (Ron Natalie <ron>) (11/23/85)

> The standard obviously didn't put much thought into anything related to
> times.  They define type "time_t" as an arithmetic type that represents
> the time, and then define a difftime(time_t time1,time_t time2) that
> computes the difference between these two arithmetic values.  Why the
> function?  Does the standard have a new arithmetic type on which the
> operation of subtraction is not allowed?

Because this isn't ADA.  Well if the specification says arithmatic
type, I'll take exception with it.  Time_t on many systems is a
struct.  Even so, consider a machine that stores the time packed in a
an int or other arithmatic type that is not just some count of ticks
since some base time.  We had one system that encoded it's time in
BCD (stupid military system required it), obviously you just can't
subtract two BCD numbers that are stored in an int and expect it to
do something meaningful.

-Ron

meissner@rtp47.UUCP (Michael Meissner) (11/24/85)

In article <171@watmath.UUCP> rbutterworth@watmath.UUCP (Ray Butterworth) writes
>
>The standard obviously didn't put much thought into anything related to
>times.  They define type "time_t" as an arithmetic type that represents
>the time, and then define a difftime(time_t time1,time_t time2) that
>computes the difference between these two arithmetic values.  Why the
>function?  Does the standard have a new arithmetic type on which the
>operation of subtraction is not allowed?
>And then they define a function gmtime(const time_t *timer) that takes
>a pointer to the arithmetic value, which it is not going to change anyway.
>Why not just take the value itself instead of the pointer?
>

   As a member of the ANSI X3J11 committee, let me point out what I saw as
the reasoning behind this.  First of all, there was great controversy as to
whether the time routines should be standerized or not.  Personally, I was
against them (some systems don't have clocks, there are systems that don't
know the difference between GMT and localtime, and what do we do with a system
in a plane or space shuttle).  As regards to gmtime, it has to be a pointer
because that's the way UNIX does it.  Historically, this is because the
original PDP-11 V6 UNIX (and earlier) did not have the long data type, and
time_t was defined as an array of two integers.  The rational behind difftime
is that the implementor does not necessarily have to store the number of
seconds since Jan. 1, 1970.  Rather the time field could be an arbitrary
encoding, and difftime would allow the user to compare two times portabily
(ie, write a make utility).  As an example of an encoding, Data General's
time field consists of 2 short integers fit into 1 long integer.  The first
is the number of days since Jan. 1, 1968, and the second is the number of
biseconds since midnight.  My C implementation actually uses the UNIX
encoding for ctime/gmtime/localtime, and provides a separate dg_ctime/
dg_localtime, but could conceivably use the native encoding.

	Michael Meissner
	Data General
	...{ ihnp4, decvax }!mcnc!rti-sel!rtp47!meissner

peter@graffiti.UUCP (Peter da Silva) (11/24/85)

> Several members of the X3J11 Committee are working on a rationale
> document that will, I hope, clarify some apparently obscure choices.
> It happens that a great deal of thought went into every aspect of
> this issue.

Yes, they took the entry for ctime from the third section of the UNIX
manual and copied it verbatim. An enourmous amount of thought must have
gone into this decision, and into the decision to pull floating point
libraries in where they're not wanted by making difftime return a float.

>> (paraphrased) why is the argument to *ctime a pointer to time_t?

The reason for the pointer is a historical dreg dating back to early Version
6 'C' compilers that couldn't pass long integers to routines.
-- 
Name: Peter da Silva
Graphic: `-_-'
UUCP: ...!shell!{graffiti,baylor}!peter
IAEF: ...!kitty!baylor!peter

tim@ISM780B.UUCP (11/26/85)

> times.  They define type "time_t" as an arithmetic type that
> represents the time, and then define a difftime(time_t
> time1,time_t time2) that computes the difference between these
> two arithmetic values.  Why the function?  Does the standard have
> a new arithmetic type on which the operation of subtraction is
> not allowed?

The difftime function first transforms both times to the frame of an observer
at Greenwich (sp?).  It needs to be a function, because the standard
C subtraction operator knows nothing about general relativity.

					Tim Smith
					ihnp4!cithep!tim
					ima!ism780!tim

mikeb@inset.UUCP (Mike Banahan) (11/26/85)

In article <171@watmath.UUCP> rbutterworth@watmath.UUCP (Ray Butterworth) writes:
>The standard obviously didn't put much thought into anything related to
>times.  They define type "time_t" as an arithmetic type that represents
>the time, and then define a difftime(time_t time1,time_t time2) that
>computes the difference between these two arithmetic values.  Why the
>function?  Does the standard have a new arithmetic type on which the
>operation of subtraction is not allowed?
>And then they define a function gmtime(const time_t *timer) that takes
>a pointer to the arithmetic value, which it is not going to change anyway.
>Why not just take the value itself instead of the pointer?

Because they realised that some systems store time in microseconds, others
in encoded formats with seconds in the bottom 6 bits, hours in the next 5,
etc ad nauseam.

The data type may be arithmetic, but its contents aren't guaranteed to be
in any given format. Hence the procedural interfaces.

Perhaps they put more thought into it than you did?
-- 
Mike Banahan, Technical Director, The Instruction Set Ltd.
mcvax!ukc!inset!mikeb

atbowler@watmath.UUCP (Alan T. Bowler [SDG]) (11/27/85)

In article <628@sftig.UUCP> lr@sftig.UUCP (L.Rosler) writes:
>Perhaps it is unrealistic to expect people who state what the "ANSI
>standard is specifying" to have read it.  The draft actually says,
>"The gmtime function returns ... a null pointer if GMT is not available."
>The presumption is that if the time() function works at all (see my
>previous posting on THAT subject), then it is reasonable to expect
>localtime() to work also.  If gmtime() is available, it must work
>as specified; otherwise it fails in a specified way.  In other words,
>"If you are going to supply gmtime functionality, do it like this...".

Ooops, I missed the line about GMTIME returning a NULL. Thank you
for pointing it out. (Now, hopefully having extracted my foot from
my mouth (-:  ) LOCALTIME, however, is still expected to return a flag
saying wheither or not daylight savings time is in effect.  Does,
   "The local time zone and Daylight Savings Time are implementation defined."
mean that I can redefine what the term "Daylight Savings Time" means and
always set the value zero?  This seems like a no win situation.
   On related problem, even assuming I have access to a daylight savings flag,
LOCALTIME, is supposed to return the daylight savings flag for some arbitrary
time_t value it is given.  Is this supposed to be today's flag, or the
value it would have had on the date being referenced?  As has been discussed
before there is no algorithm that will predict when daylight time is in effect
since it is in many places under control of local politicians.
  Is there some reading of the standard, or some more lines that can be added
telling me what to implement on a machine which has no access to
a daylight savings time flag.