main() in C90

A

Army1987

jacob said:
That is why it is specified that you should pass a pointer
to a double and NOT a pointer to a float. In asctime() however
NO SPECIFICATION about maximum data ranges is done at ALL!

Yes, there is one, even though an implicit one.
(But I'd prefer that an explicit one is added, too: "If one of the members
of *timeptr is not in the range specified in 7.23.1, or if timeptr-> is
not in the range [-2899, 8099], the behavior is undefined." That would be
so easy.)
 
A

Army1987

Billy said:
In reality, "void main()" is also valid.

Some compilers issue a warning for this, but you can safely ignore this
warning in 99.999999% or six sigma of the time.
Six sigma what? That's not a normally distributed variable. :)
 
C

CBFalconer

Army1987 said:
jacob said:
That is why it is specified that you should pass a pointer
to a double and NOT a pointer to a float. In asctime() however
NO SPECIFICATION about maximum data ranges is done at ALL!

Yes, there is one, even though an implicit one. (But I'd prefer
that an explicit one is added, too: "If one of the members of
*timeptr is not in the range specified in 7.23.1, or if timeptr->
is not in the range [-2899, 8099], the behavior is undefined."
That would be so easy.)

Totally unnecessary. A struct tm is built by mktime, and the range
of components of a struct tm is specified by the standard. See
section 7.23.1. The function of mktime is to convert the system
specific timer format to a known system independent format.

If you build your own struct tm and fail to adhere to the
specification, the problem is all yours. It is analagous to
omitting the final '\0' from a string.
 
C

CBFalconer

Chris said:
.... snip ...


N869.txt is NOT a standard

Undefined behaviour cut..........

You can't have it both ways. .

Well, I could omit the informative comment about the source and
depend upon you to do a word for word comparison with the 'actual
standard'. Would you prefer that?
 
C

CBFalconer

James said:
CBFalconer wrote:
...

In what way does the behavior of an implementation of asctime()
fail to be equivalent to that algorithm, when the behavior of
that algorithm is defined, if the implementation uses an
overlong buffer?

As others have pointed out, the presence of an overlong buffer is
not detectable, since asctime never places a string that occupies
over 26 bytes (length 25) in it. However a string of less than 26
byte capacity would be immediately detectable by causing undefined
behaviour. It is up to you to detect that, and I don't want the
task (portable).
 
C

CBFalconer

Keith said:
.... snip ...

There are two kinds of conforming C implementations, hosted and
freestanding. You're not likely to run into a freestanding
implementation unless you work on embedded systems (though it's
been argued that some MS Windows C implementations are really
freestanding).

Since those 'implementations' lack any form whatsoever of the main
function, that seems to be an adequate argument that they are not
written in C for a hosted implementation. This seems to make MS
one of the largest vendors of embedded code.
 
C

CBFalconer

Army1987 said:
Six sigma what? That's not a normally distributed variable. :)

I think it is more important to identify the Bong comment as pure
imagination, apart from embedded (non-hosted) systems. I.e. bong
it.
 
C

Chris Hills

Ben Bacarisse said:
Nether can you. You are on record as objecting to pedantic postings
that are correct but unhelpful.
And it is CBF who is a prime example of doing this.
If there a difference between the
cited text and the published standard?

That is the question... it is as CFB woudl say "Undefined Behaviour"

Actually in this case they are the same *at the moment*.
 
K

Keith Thompson

jacob navia said:
Of course the workaround is easy, and lcc-win will never
overflow the buffer.

Glad to hear it. So what exactly does it do with tm_year==100000?
I'm just curious.
BUT tell me, why do we have to program workarounds for the standard?

What kind of standard is this one that needs workarounds for its BUGS?

What bugs?

C99 7.1.4p1:

Each of the following statements applies unless explicitly stated
otherwise in the detailed descriptions that follow: If an argument
to a function has an invalid value (such as a value outside the
domain of the function, or a pointer outside the address space of
the program, or a null pointer, or a pointer to non-modifiable
storage when the corresponding parameter is not const-qualified)
or a type (after promotion) not expected by a function with
variable number of arguments, the behavior is undefined.

C99 7.23.1p4:

The range and precision of times representable in clock_t and
time_t are implementation-defined. The tm structure shall contain
at least the following members, in any order. The semantics of the
members and their normal ranges are expressed in the comments.

It's not a huge leap to conclude that a value outside its "normal
range" constitute "an invalid value (such as a value outside the
domain of the function". Note that mktime() can accept values outside
their normal ranges, and this is explicitly stated. And if you
examine the sample algorithm given in the standard, it's not hard to
figure out which arguments will overflow the buffer.

asctime() is hardly the only function that exhibits undefined behavior
if you give it invalid arguments. Consider calling strlen() with a
pointer to the first element of an array that contains no '\0'
characters, or calling free() with a pointer that's already been
freed, or fwrite() with a closed file.

I agree that the limitations on asctime() should have been stated more
clearly in the standard, but on the other hand the standard is not a
tutorial. All the information is there; you just have to put it
together. I would expect a good tutorial or reference work to mention
this more explicitly.

I also agree that the required implementation of asctime() should
handle any possible values of the members of *timeptr without
undefined behavior, but I just don't think it's that big a deal.
If it were up to me, it would be changed.

But, as I've asked before, have you ever seen an actual program (one
not written for the purpose of demonstrating this problem) fail
because of this?
 
K

Keith Thompson

Chris Hills said:
[...]
If there a difference between the
cited text and the published standard?

That is the question... it is as CFB woudl say "Undefined Behaviour"

Actually in this case they are the same *at the moment*.

At the moment? N869.txt isn't going to change, and neither is the C99
standard, though the latter may be superseded by a new version of the
standard.

If I quoted a passage directly from ISO/IEC 9899:1999 (E), the C99
standard itself, would you complain that the quotation is only correct
"at the moment"?
 
H

Harald van Dijk

Glad to hear it. So what exactly does it do with tm_year==100000? I'm
just curious.

I don't know about lcc-win32, but on my system with 32-bit ints, glibc
reserves a buffer of 114 bytes, which is capable of holding the result
for the absolute largest values that could be put in a struct tm if int
had 64 bits.
 
K

Keith Thompson

Army1987 said:
jacob said:
That is why it is specified that you should pass a pointer
to a double and NOT a pointer to a float. In asctime() however
NO SPECIFICATION about maximum data ranges is done at ALL!

Yes, there is one, even though an implicit one.
(But I'd prefer that an explicit one is added, too: "If one of the members
of *timeptr is not in the range specified in 7.23.1, or if timeptr-> is
not in the range [-2899, 8099], the behavior is undefined." That would be
so easy.)

Except that, for an implementation that uses exactly the sample
implementation in the standard, you *can* call asctime() with some
member values outside the ranges specified in 7.23.1 and get well
defined behavior. (Consider a tm_sec value of 99, for example, or a
5-digit year combined with a 1-digit tm_sec.)

So this would be a change to the standard, though I doubt that it
would break any existing code.

The standard could say something like this:

If all the members of *timeptr (other than tm_yday and tm_isdst,
which are ignored) have values in their normal ranges as specified
in 7.23.1, the behavior of asctime() is equivalent to the
following algorithm; otherwise, the behavior is undefined.

Again, this would introduce undefined behavior in some corner cases
that are well defined in the current standard, but it would be
simpler.

On the other hand, one could argue based on 7.1.4p1 that such corner
cases are already undefined behavior.
 
K

Keith Thompson

CBFalconer said:
Since those 'implementations' lack any form whatsoever of the main
function, that seems to be an adequate argument that they are not
written in C for a hosted implementation. This seems to make MS
one of the largest vendors of embedded code.

I thought it was still possible to write "int main(void)" (if you want
a program that uses a console rather than the GUI).
 
I

Ioannis Vranos

Keith said:
I thought it was still possible to write "int main(void)" (if you want
a program that uses a console rather than the GUI).


int main(void) does not imply a console necessarily, but this is usually
the case.
 
R

Richard Heathfield

CBFalconer said:
A struct tm is built by mktime,

The Standard does not require this. It's perfectly feasible (and
commonplace) for people to roll their own struct tm objects. Nor is mktime
the only standard function that builds a struct tm.
 
R

Richard Heathfield

Chris Hills said:
That is the question... it is as CFB woudl say "Undefined Behaviour"

Actually in this case they are the same *at the moment*.

In which case they've been the same since 1999, and will remain the same
until the next C Standard is published, which may be in another ten or
fifteen or twenty years.

If someone cites a draft and you can demonstrate that their argument is
wrong because it relies on wording that no longer exists or which has
changed, fine - but an across-the-board refusal to countenance quotes from
draft documents is just silly. Yes, we accept that a draft is not
authoritative in the way that a final standard is, but on the other hand
it is not a worthless document (otherwise it would not have been
produced). A final standard trumps a draft, to be sure, but an otherwise
valid argument based on a draft doc is only invalidated if the final
standard differs from the draft in the relevant section(s).
 
R

Richard Heathfield

Keith Thompson said:
I thought it was still possible to write "int main(void)" (if you want
a program that uses a console rather than the GUI).

Yes, so Visual C++ (which is the name they give to their C compiler, btw,
and apparently it also provides support for another language) is both a
hosted /and/ a freestanding implementation. What's more, on early versions
of Visual Studio you could even target MS-DOS, which - arguably -
constitutes cross-compilation.

Microsoft is not the only company to provide both freestanding and hosted
implementations for Windows. Certainly Borland (or whatever they call
themselves nowadays[1]) also does this, and it is likely that other
Windows implementors follow suit.


[1] What is it with Borland and marketing? I mean, yes, I'm glad they're
not dominated by market-think, but you'd think they'd be bright enough to
recognise the importance of the Borland brand name. Inprise sank without
trace, and CodeGear is likely to do the same. Sheesh, Borland - *please*
don't kill yourself.
 
C

CBFalconer

Richard said:
CBFalconer said:


The Standard does not require this. It's perfectly feasible (and
commonplace) for people to roll their own struct tm objects. Nor
is mktime the only standard function that builds a struct tm.

I had the impression (possibly wrong) that the functions that
created a struct tm operated on unspecified format system data, and
thus had to be part of the library. In light of that I considered
any other method to be an extension, whose correctness is entirely
up to the extender.
 
K

Keith Thompson

CBFalconer said:
I had the impression (possibly wrong) that the functions that
created a struct tm operated on unspecified format system data, and
thus had to be part of the library. In light of that I considered
any other method to be an extension, whose correctness is entirely
up to the extender.

Sure, gmtime() and localtime() have to know what a time_t looks like,
and therefore have to be part of the library. But a user function
that creates a struct tm is just a user function; it's not part of the
implementation, and therefore it's not an extension.
 
R

Richard Heathfield

CBFalconer said:
I had the impression (possibly wrong) that the functions that
created a struct tm operated on unspecified format system data

They may well do, but that's not a prerequisite for building a struct tm -
the spec for struct tm is spelled out in the Standard (and in K&R2), and
it's easy to roll your own. Right now, for example, I could represent
today's date and time as follows, and then use (a pointer to) it as
perfectly legal and well-defined input to, say, strftime:

#include <time.h>

int main(void)
{
struct tm now;
now.tm_isdst = 0;
now.tm_yday = 20;
now.tm_wday = 1;
now.tm_year = 108;
now.tm_mon = 0;
now.tm_mday = 21;
now.tm_hour = 8;
now.tm_min = 44;
now.tm_sec = 59;
now.tm_min = 45;
now.tm_sec = 09;
now.tm_sec = 16;
now.tm_sec = 23;
now.tm_sec = 31;
now.tm_sec = 39;
now.tm_sec = oh I give up. Okay, you're right - it can't be done.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top