What does ((time_t)-1) mean?

R

Richard Tobin

The type time_t is defined in the C language standard. The fact that
time() on the OP's system is in section 2 of the manual pages does not
change that.
[/QUOTE]
That will teach me to trust the manual pages rather than reading the
standard...

If you man page said that time() conforms to Posix, it was correct.
It merely omitted to say it also conforms to ISO C. Posix time() is
more rigidly defined that C's version - it specifies that it returns
seconds since Jan 1 1970.

-- Richard
 
J

James Kuyper

That response was merely a pointless attempt to show how clever Kenny
is, without being in anyway useful to the OP. I'm sure Kenny doesn't
care, but all it did was make him look silly, not clever.
Is it legal to declare a variable named "time_t"? True, you have
not included <time.h> which is why it "works".

Are you allowed to repurpose a type/variable/macro defined by the
standard, as long as you don't use anything related to the way
the standard defines them?

The standard's time_t typedef has file scope, and is in the name space
of ordinary identifiers. It "... is reserved for use as a macro name and
as an identifier with file scope in the same name space", but only " if
any of its associated headers is included." (7.1.3p1). Therefore, even
if he had #included the header, use in any scope other than file scope
is fine. Since he didn't #include the header, the issue wouldn't even
come up at file scope.
If, for example, defining your own printf() function invokes UB,
even if you never make reference (direct or otherwise) to the
standard's printf() function, doesn't the same hold true for the
time_t typedef?

The printf() function name is an identifier with external linkage; the
rules are different in that case. such identifiers "... are always
reserved for use as identifiers with external linkage ..." (7.1.3p1).
Note that you can still define your own printf identifier, so long as
you declare it 'static', giving it internal linkage, or use it as an
identifier with no linkage (like a typedef). However, if you declare it
static then you cannot #include <stdio.h> in the same translation unit,
because then you would have declarations of the same identifier with
internal and external linkage in the same translation unit (6.2.2p7).

Whether either of these cases is a good idea is a different matter - as
a general rule I would recommend avoiding any alternative definition of
names defined in the standard library, even in contexts where it is
legal to do so. But it is legal to use time_t and printf in the manner
described above.
 
C

Charlie Gordon

Eric Sosman said:
If (time_t)-1 < INT_MAX, the cast is required. (I've never
seen and may never see a system where this condition holds, but
why take even a small risk if it's unnecessary?)

if time_t is signed, the condition holds and the cast is not required.
 
R

Richard Tobin

If (time_t)-1 < INT_MAX, the cast is required. (I've never
seen and may never see a system where this condition holds, but
why take even a small risk if it's unnecessary?)
[/QUOTE]
if time_t is signed, the condition holds and the cast is not required.

Likewise if time_t is a floating-point type.

-- Richard
 
K

Kenneth Brody

Harald said:
Redefining external symbols is a bad idea, but defining your own symbols
which happen to have the same name as standard symbols is allowed.

On the other hand, my compiler gives no warnings (even with warnings
at max) and displays "4" and "-1" for the following code. Of course,
as has been said here numerous times, "works as expected" is a valid
outcome for UB.

I'm still not convinced one way or the other. (Though I do know not
to actually use such a construct in the first place in any "real"
code.)

==========
#include <stdio.h>
#include <time.h>

void foo(void)
{
time_t time_t = 5;
printf("%ld\n",(long)( (time_t)-1 ) );
}
void bar(void)
{
printf("%ld\n",(long)( (time_t)-1 ) );
}

int main(void)
{
foo();
bar();
}
==========

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Kenneth Brody

James said:
Kenny McCormack wrote: [...]
This (perfectly legal) program says that the answer to your question is 5:

#include <stdio.h>
int main(void)
{
int time_t = 6;
printf("The result is %d\n",((time_t)-1));
return 0;
}

That response was merely a pointless attempt to show how clever Kenny
is, without being in anyway useful to the OP. I'm sure Kenny doesn't
care, but all it did was make him look silly, not clever.

Well, Kenny's intentions aside, it does bring up a valid question
regarding variables with the same name as a typedef. My compiler
allows a variable named "time_t" even with <time.h> included. In
such a case, "(time_t)-1" is (to me) ambiguous. My compiler treats
it as "the variable time_t, minus one", but it could (unless the
standard says otherwise) interpret as "cast negative one to the
time_t type".

I'm wondering what, if anything, the standard says about this.

[...]
The standard's time_t typedef has file scope, and is in the name space
of ordinary identifiers. It "... is reserved for use as a macro name and
as an identifier with file scope in the same name space", but only " if
any of its associated headers is included." (7.1.3p1). Therefore, even
if he had #included the header, use in any scope other than file scope
is fine. Since he didn't #include the header, the issue wouldn't even
come up at file scope.

Let's ignore standard-defined typedefs for the moment. What about:

typedef int my_int_t;
my_int_t my_int_t = 4;
...
printf("%d\n", (my_int_t)-1 );

[...]

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

On the other hand, my compiler gives no warnings (even with warnings at
max) and displays "4" and "-1" for the following code. Of course, as
has been said here numerous times, "works as expected" is a valid
outcome for UB.

I'm still not convinced one way or the other. (Though I do know not to
actually use such a construct in the first place in any "real" code.)

==========
#include <stdio.h>
#include <time.h>

void foo(void)
{
time_t time_t = 5;
printf("%ld\n",(long)( (time_t)-1 ) ); }
void bar(void)
{
printf("%ld\n",(long)( (time_t)-1 ) ); }

int main(void)
{
foo();
bar();
}
==========

This does not redefine any standard symbol. This is a case of defining
your own symbols which happen to have the same name as standard symbols.
An example:

#include <stdio.h>

void time(void) /* error: conflicts with time_t time(time_t *), since
both are external symbols */
{}

static int printf; /* error: conflicts with int printf(const char
*restrict, ...), since both have file scope */

int time_t; /* okay: doesn't conflict with time_t, since <time.h>'s
version isn't external and isn't defined */

int main(int fread, char *fopen[]) /* okay: doesn't conflict with fread
or fopen, since neither is declared as an external symbol */
{
#undef stderr
#define stderr return 0 /* error: redefines the standard symbol stderr,
since <stdio.h> is included and defines stderr as a macro */
stderr;
}
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

Let's ignore standard-defined typedefs for the moment. What about:

typedef int my_int_t;
my_int_t my_int_t = 4;
...
printf("%d\n", (my_int_t)-1 );

[...]

If the typedef and the object are defined in the same block (or both at
file scope), this is not allowed. Otherwise, it is.
 
S

santosh

$)CHarald van D)&k said:
Let's ignore standard-defined typedefs for the moment. What about:

typedef int my_int_t;
my_int_t my_int_t = 4;
...
printf("%d\n", (my_int_t)-1 );

[...]

If the typedef and the object are defined in the same block (or both
at file scope), this is not allowed. Otherwise, it is.

In that case it's rather surprising that gcc, at least, doesn't produce
any diagnostic even when '-Wall', '-W', '-ansi' and '-pedantic' are
provided.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

$)CHarald van D)&k said:
Let's ignore standard-defined typedefs for the moment. What about:

typedef int my_int_t;
my_int_t my_int_t = 4;
...
printf("%d\n", (my_int_t)-1 );

[...]

If the typedef and the object are defined in the same block (or both at
file scope), this is not allowed. Otherwise, it is.

In that case it's rather surprising that gcc, at least, doesn't produce
any diagnostic even when '-Wall', '-W', '-ansi' and '-pedantic' are
provided.

Do you mean that it doesn't produce any diagnostic in the same block, or
in different blocks? If the former, that's a bug, and I encourage you to
report it. The version of gcc I'm using reports an unconditional error
for this. If the latter, the code is perfectly valid, so why should it
complain? There are enough cases where hiding the outer symbol this way
is intentional to not warn by default, but if you do want the warning,
there's an option just for that (-Wshadow).
 
O

Old Wolf

On the other hand, my compiler gives no warnings (even with warnings
at max) and displays "4" and "-1" for the following code. Of course,
as has been said here numerous times, "works as expected" is a valid
outcome for UB.

void bar(void)
{
printf("%ld\n",(long)( (time_t)-1 ) );
}

A minor point: this causes implementation-defined
behaviour (or raising a signal, in C99) if time_t
is an unsigned long (or a larger unsigned type).
 
K

Keith Thompson

loudking said:
I don't quite understand what does ((time_t)-1) mean when I execute
"man 2 time"

RETURN VALUE
On success, the value of time in seconds since the Epoch is
retu
rned.
On error, ((time_t)-1) is returned, and errno is set
appropriately
.
Could anybody tell me its meaning please?

And, is my way of checking return value correct?

time_t now;

time(&now);
if (!now) {
fprintf(stderr, "Unable to fetch time information: %s
\n",
strerror(errno));
return 1;
}

To clear up some confusion that's probably already been cleared up in
this thread:

The time function and the time_t type are standard C. The're declared
in the standard header <time.h>. If you want to use them, you need to
``#include <time.h>''. (If you don't ``#include <time.h>'', you can
get away with using the name "time_t" for your own purposes, but it
would be a very bad idea -- and that's not what you asked about
anyway.)

time_t is required by the C standard to be an arithmetic type. It
could be a signed integer type, an unsigned integer type, or a
floating-point type. It represents times, but the manner in which it
does so is not specified by the standard. (POSIX imposes stricter
requirements; for details, consult your system's documentation and/or
comp.unix.programmer.)

``-1'' is, of course, an integer expression of type int with the value
negative one. ``((time_t)-1)'' applies a cast operator to the value
-1, i.e., it converts the value from type int to type time_t. If
time_t is signed, the result is -1. If time_t is unsigned, the result
is the maximum value of the unsigned type. If time_t is
floating-point, the result is -1.0.

The value ``((time_t)-1)'' was chosen arbitrarily as a unique value
that indicates an error in the time() function. There are some
disadvantages to this choice; in particular, for some implementations
-1 represents an actual time. IMHO it would have been better to
define a symbolic constant and let the implementation choose a value.
But much of the C library definition is driven by historical practice,
so this is what we're stuck with.

To answer your second question, no, ``if (!now)'' is not the way to
test whether time time() function failed. When an expression is used
as a condition, it's considered false if it's equal to zero, true
otherwise. You need to test whether ``now'' is equal to -1, not to 0.
 
C

Charlie Gordon

Old Wolf said:
A minor point: this causes implementation-defined
behaviour (or raising a signal, in C99) if time_t
is an unsigned long (or a larger unsigned type).

'minor' does not begin to describe how minuscule it is in real life.
 
R

Richard Heathfield

Charlie Gordon said:
'minor' does not begin to describe how minuscule it is in real life.

By "real life", presumably, you mean "systems that Charlie Gordon has
worked on".
 
C

Charlie Gordon

Richard Heathfield said:
Charlie Gordon said:


By "real life", presumably, you mean "systems that Charlie Gordon has
worked on".

I have probably worked on more different systems than you have.
Can anyone name a real-life system where casting a time_t or whatever
unsigned type to long causes a signal to be raised, or any kind of
surprising behaviour?
 
R

Richard Heathfield

Charlie Gordon said:
I have probably worked on more different systems than you have.

Yes, you probably have. Er, so what? It is clear that you have never worked
on a system where the conversion of a time_t to a long int causes a
problem. Otherwise, you surely would not have answered as you did.
Can anyone name a real-life system where casting a time_t or whatever
unsigned type to long causes a signal to be raised, or any kind of
surprising behaviour?

Wrong question, or at least it's an incomplete question. What it's missing
is this: "...or could a computer manufacturer, for commercial or
engineering reasons of its own, release a system at some point in the
future that would break the above code with unfortunate consequences
despite the provision and use of a conforming ISO C compiler for that
system?"

And the answer is yes.
 
C

Charlie Gordon

Richard Heathfield said:
Charlie Gordon said:


Yes, you probably have. Er, so what? It is clear that you have never
worked
on a system where the conversion of a time_t to a long int causes a
problem. Otherwise, you surely would not have answered as you did.

Have you ever worked on one?
Your answer below indicates you haven't.
Such systems are either obsolete, hypothetical or doomed.
Wrong question, or at least it's an incomplete question. What it's missing
is this: "...or could a computer manufacturer, for commercial or
engineering reasons of its own, release a system at some point in the
future that would break the above code with unfortunate consequences
despite the provision and use of a conforming ISO C compiler for that
system?"

And the answer is yes.

Porting "real-life" programs to this architectural oddity would be a
pointless nightmare.
 
R

Richard Heathfield

Charlie Gordon said:
"Richard Heathfield" a écrit...

Have you ever worked on one?
Your answer below indicates you haven't.

No, it indicates at most that I have no idea whether or not I have worked
on such a system. It is entirely possible that I have done so without
realising it, and never found out because I didn't take liberties with
time_t.
Such systems are either obsolete, hypothetical or doomed.

Hypothetical systems have a nasty habit, occasionally, of becoming real
systems. Planning for the future is part of portable programming, and it's
one reason we have standards in the first place - so that our code
*doesn't* break on new systems.

<snip>
 
K

Kenneth Brody

Old said:
A minor point: this causes implementation-defined
behaviour (or raising a signal, in C99) if time_t
is an unsigned long (or a larger unsigned type).

What part of C99 would raise a signal if time_t is an unsigned long
or larger? Is it the "loss of precision" cause by casting it to a
(signed) long?

Also, going way back to the OP, note that 7.23.2.4p3 refers to
"(time_t)(-1)", and not "((time_t)-1)". (Note the parens around "-1",
making it unambiguous that "(time_t)" is a cast, and not a variable
name.)

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Kenneth Brody

$)CHarald van D)&k said:
$)CHarald van D)&k said:
typedef int my_int_t;
my_int_t my_int_t = 4;
...
printf("%d\n", (my_int_t)-1 );

[...]

If the typedef and the object are defined in the same block (or both at
file scope), this is not allowed. Otherwise, it is.

In that case it's rather surprising that gcc, at least, doesn't produce
any diagnostic even when '-Wall', '-W', '-ansi' and '-pedantic' are
provided.

Do you mean that it doesn't produce any diagnostic in the same block, or
in different blocks? If the former, that's a bug, and I encourage you to
report it. The version of gcc I'm using reports an unconditional error
for this. If the latter, the code is perfectly valid, so why should it
complain? There are enough cases where hiding the outer symbol this way
is intentional to not warn by default, but if you do want the warning,
there's an option just for that (-Wshadow).

Here is my complete source file:

==========
#include <stdio.h>

typedef int my_int_t;

int main(void)
{
my_int_t my_int_t = 5;

printf("%d\n",(my_int_t)-1);

return 0;
}
==========

$ gcc --version
egcs-2.91.66

$ gcc -Wall -W -ansi -pedantic foo.c
$ ./a.out
4
$

==========

Using MSVC 6.0, no warnings appear with "/W4", and it also produces
the output "4".

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 

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

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top