Implicit assumptions (was: Re: Some fun with -O2)
Walter von Entferndt
walter.von.entferndt at posteo.net
Mon Jan 18 11:47:15 UTC 2021
Now to test the above solution (and out of curiosity), I tried it with
*time_t* changed to *signed char* in /guess_time_t_max()/ and it gave:
DEBUG: prec(signed_char) = 8
schar_t_max = 0xFFFFFFFFFFFFFFFF
sizeof(schar_t) = 1 byte
precision = 63 bit
padding = -56 bit
bits per byte = 8 bit
Exitcode 1
which is from the check I added at the start of /main()/ (0xFF = -1, anyway it
would fall into an endless loop because the delta gets =0 then), while with
*signed int* instead of *time_t* it gives:
DEBUG: prec(signed int) = 32
xxx_t_max = 0x7FFFFFFF
sizeof(xxx_t) = 4 byte
precision = 63 bit
padding = -32 bit
bits per byte = 8 bit
and the program runs ok (I have set /printexitvalue/ in my tcsh). It does not
concern me that the program fails if *sizeof(time_t)* = 1, but I didn't expect
these other curiosities. Now I went back to a simple switch-on-storage-width,
that I believe will cover most (all?) cases except when *time_t* is a floating
point. Rationale: the standard says *time_t* is either a floating point or
integer type, and from that I conclude it's equivalent to one of the standard
types. I tested with time_t faked beeing 1 (char), 2 (short), 4 (int) and 8
(standard on my 64-bit Intel). Of course with a 1-byte *time_t* it falls into
the endless loop as expected.
At Montag, 18. Januar 2021, 00:31:46 CET, Mark Millard wrote:
> On 2021-Jan-17, at 13:25, Walter von Entferndt
<walter.von.entferndt at posteo.net> wrote:
> > . . .
> > - for (j = 1; 0 < j; j *= 2)
> > + /* NOTE This does not reach very large values > time_t_max/2
> > + neither the (susceptible for overflow) version
> > + for (j = 1; 0 < j; j *= 2) does */
> > + for (i = j = 1; i < PRECISION(INT_MAX); i++, j *= 2)
>
> I'm unclear on why INT_MAX here.
>
Because i and j are *int* s. My intent was to avoid sign overflow, which can
happen silently (j *= 2), but the standard says it's undefined, and that was
the starting point of this thread. The genuine version relies on silent
overflow, which is sub-optimal. The above version is (intentionally) not
equivalent to the genuine one. Instead this would do what the author intended
(from my understanding), but without any chance for overflow:
for (i = 0; i < PRECISION (INT_MAX); i++)
{
j = (int) 1 << i;
bigtime_test (j);
}
bigtime_test (INT_MAX);
}
The point is that on sign overflow j switches to INT_MIN, and the author
expects the difference INT_MIN - 1 = INT_MAX, which is reasonable, but
mathematically bogus, as well as j *= 2 will mathematically always be >0 as
long you start with a positive value. And today's clever optimizing compilers
do what you write, not what you intend; e.g. produce an endless loop when you
write an expression that it can prove to be always true as the loop condition.
> It leaves me to wonder about using something that
> invovled PRECISION(time_t_max).
>
You can't do that as long you don't know if it's really the maximum value.
In the code above (i < PRECISION (INT_MAX)): to account for any padding bits.
To be portable.
> > +/*! vi: set ai tabstop=8 shiftwidth=2: */
When fixing code, I think it's polite to adopt the genuine formating. Since
in this case it's rather unusual, I'm telling my editor to use sw=2 (I use 4).
--
=|o) "Stell' Dir vor es geht und keiner kriegt's hin." (Wolfgang Neuss)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: check_mktime.c.patch
Type: text/x-patch
Size: 5369 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/freebsd-hackers/attachments/20210118/4decb044/attachment.bin>
More information about the freebsd-hackers
mailing list