Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #164237 > unrolled thread
| Started by | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| First post | 2022-01-03 14:15 -0300 |
| Last post | 2022-01-30 23:53 -0800 |
| Articles | 16 on this page of 36 — 11 participants |
Back to article view | Back to comp.lang.c
does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-03 14:15 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Bart <bc@freeuk.com> - 2022-01-03 17:32 +0000
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-15 22:09 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2022-01-03 10:06 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-15 22:12 -0300
Re: does a double cast to unsigned makes sense in any circumstance? James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-01-15 23:12 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-01-20 19:37 -0800
Re: does a double cast to unsigned makes sense in any circumstance? "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2022-01-21 09:35 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-01-21 17:19 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Bonita Montero <Bonita.Montero@gmail.com> - 2022-01-03 19:31 +0100
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-15 22:14 -0300
Re: does a double cast to unsigned makes sense in any circumstance? James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-01-15 23:24 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-16 13:30 -0800
Re: does a double cast to unsigned makes sense in any circumstance? James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-01-16 23:25 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-17 09:43 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-17 13:59 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-28 22:13 -0300
Re: does a double cast to unsigned makes sense in any circumstance? James Kuyper <jameskuyper@alumni.caltech.edu> - 2022-01-28 21:29 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-02-03 22:28 -0800
Re: does a double cast to unsigned makes sense in any circumstance? "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2022-02-04 10:43 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-28 19:37 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Manfred <noname@add.invalid> - 2022-01-30 03:45 +0100
Re: does a double cast to unsigned makes sense in any circumstance? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2022-01-30 00:01 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Richard Damon <Richard@Damon-Family.org> - 2022-01-30 12:59 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-17 09:41 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Richard Damon <Richard@Damon-Family.org> - 2022-01-03 14:37 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-15 22:15 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Richard Damon <Richard@Damon-Family.org> - 2022-01-15 20:55 -0500
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-17 09:44 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Bonita Montero <Bonita.Montero@gmail.com> - 2022-01-16 05:13 +0100
Re: does a double cast to unsigned makes sense in any circumstance? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2022-01-15 18:53 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Meredith Montgomery <mmontgomery@levado.to> - 2022-01-17 09:46 -0300
Re: does a double cast to unsigned makes sense in any circumstance? Bonita Montero <Bonita.Montero@gmail.com> - 2022-01-29 16:57 +0100
Re: does a double cast to unsigned makes sense in any circumstance? Öö Tiib <ootiib@hot.ee> - 2022-01-29 09:54 -0800
Re: does a double cast to unsigned makes sense in any circumstance? Bonita Montero <Bonita.Montero@gmail.com> - 2022-01-30 13:17 +0100
Re: does a double cast to unsigned makes sense in any circumstance? Öö Tiib <ootiib@hot.ee> - 2022-01-30 23:53 -0800
Page 2 of 2 — ← Prev page 1 [2]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2022-01-28 19:37 -0800 |
| Message-ID | <87fsp7ky9m.fsf@nosuchdomain.example.com> |
| In reply to | #164701 |
Meredith Montgomery <mmontgomery@levado.to> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>> Meredith Montgomery <mmontgomery@levado.to> writes:
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>>>> [...]
>>>>> "... the value is converted by repeatedly adding ... one more than the
>>>>> maximum value that can be represented in the new type until the value is
>>>>> in the range of the new type." (6.3.1.3p2).
>>>>>
>>>>> It's the other direction that's dangerous: conversion of an integer
>>>>> value to a signed integer type that is not representable in that type
>>>>> has undefined behavior.
>>>>
>>>> No, converting an out-of-range integer value to a signed integer type
>>>> yields an implementation-defined result or raises an
>>>> implementation-defined signal. (C99 added the option of raising a
>>>> signal; in my opinion that was a bad idea.)
>>>
>>> Just curious --- why do you think a signal is a bad idea?
>>
>> A signal isn't inherently a bad idea, particularly if portable code can
>> handle it. But the fact that the signal is implementation-defined makes
>> that impossible. (And freestanding implementations needn't support
>> <signal.h>.)
>
> What's a freestanding implementation?
See section 4 of any edition of the C standard. I usually use
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf, a draft
that's close to C11.
The two forms of *conforming implementation* are hosted and
freestanding. A *conforming hosted implementation* shall accept any
strictly conforming program. A *conforming freestanding implementation*
shall accept any strictly conforming program in which the use of the
features specified in the library clause (clause 7) is confined to the
contents of the standard headers <float.h>, <iso646.h>, <limits.h>,
<stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, and
<stdnoreturn.h>. A conforming implementation may have extensions
(including additional library functions), provided they do not alter
the behavior of any strictly conforming program.
Basically a hosted implementation is the kind that you're most likely to
encounter. It generates code that runs under an operating system, and
it supports the entire standard library. A freestanding implementation
targets an embedded system that might not have an operating system at
all. The only standard library headers that must be supported are the
ones that don't declare any functions. A freestanding implementation
might provide some library functions, but it isn't required to.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2022-01-30 03:45 +0100 |
| Message-ID | <st4u3j$st8$1@gioia.aioe.org> |
| In reply to | #164709 |
On 1/29/2022 4:37 AM, Keith Thompson wrote: > Meredith Montgomery <mmontgomery@levado.to> writes: >> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: >>> Meredith Montgomery <mmontgomery@levado.to> writes: >>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: >>>>> James Kuyper <jameskuyper@alumni.caltech.edu> writes: >>>>> [...] >>>>>> "... the value is converted by repeatedly adding ... one more than the >>>>>> maximum value that can be represented in the new type until the value is >>>>>> in the range of the new type." (6.3.1.3p2). >>>>>> >>>>>> It's the other direction that's dangerous: conversion of an integer >>>>>> value to a signed integer type that is not representable in that type >>>>>> has undefined behavior. >>>>> >>>>> No, converting an out-of-range integer value to a signed integer type >>>>> yields an implementation-defined result or raises an >>>>> implementation-defined signal. (C99 added the option of raising a >>>>> signal; in my opinion that was a bad idea.) >>>> >>>> Just curious --- why do you think a signal is a bad idea? >>> >>> A signal isn't inherently a bad idea, particularly if portable code can >>> handle it. But the fact that the signal is implementation-defined makes >>> that impossible. (And freestanding implementations needn't support >>> <signal.h>.) >> >> What's a freestanding implementation? > > See section 4 of any edition of the C standard. I usually use > http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf, a draft > that's close to C11. > > The two forms of *conforming implementation* are hosted and > freestanding. A *conforming hosted implementation* shall accept any > strictly conforming program. A *conforming freestanding implementation* > shall accept any strictly conforming program in which the use of the > features specified in the library clause (clause 7) is confined to the > contents of the standard headers <float.h>, <iso646.h>, <limits.h>, > <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, and > <stdnoreturn.h>. A conforming implementation may have extensions > (including additional library functions), provided they do not alter > the behavior of any strictly conforming program. > > Basically a hosted implementation is the kind that you're most likely to > encounter. It generates code that runs under an operating system, and > it supports the entire standard library. A freestanding implementation > targets an embedded system that might not have an operating system at > all. The only standard library headers that must be supported are the > ones that don't declare any functions. A freestanding implementation > might provide some library functions, but it isn't required to. > A freestanding implementation might also target the OS itself of a common system (not necessarily embedded), right?
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2022-01-30 00:01 -0800 |
| Message-ID | <87bkztlki5.fsf@nosuchdomain.example.com> |
| In reply to | #164727 |
Manfred <noname@add.invalid> writes:
> On 1/29/2022 4:37 AM, Keith Thompson wrote:
>> Meredith Montgomery <mmontgomery@levado.to> writes:
>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>> Meredith Montgomery <mmontgomery@levado.to> writes:
>>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>>>>>> James Kuyper <jameskuyper@alumni.caltech.edu> writes:
>>>>>> [...]
>>>>>>> "... the value is converted by repeatedly adding ... one more than the
>>>>>>> maximum value that can be represented in the new type until the value is
>>>>>>> in the range of the new type." (6.3.1.3p2).
>>>>>>>
>>>>>>> It's the other direction that's dangerous: conversion of an integer
>>>>>>> value to a signed integer type that is not representable in that type
>>>>>>> has undefined behavior.
>>>>>>
>>>>>> No, converting an out-of-range integer value to a signed integer type
>>>>>> yields an implementation-defined result or raises an
>>>>>> implementation-defined signal. (C99 added the option of raising a
>>>>>> signal; in my opinion that was a bad idea.)
>>>>>
>>>>> Just curious --- why do you think a signal is a bad idea?
>>>>
>>>> A signal isn't inherently a bad idea, particularly if portable code can
>>>> handle it. But the fact that the signal is implementation-defined makes
>>>> that impossible. (And freestanding implementations needn't support
>>>> <signal.h>.)
>>>
>>> What's a freestanding implementation?
>> See section 4 of any edition of the C standard. I usually use
>> http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf, a draft
>> that's close to C11.
>> The two forms of *conforming implementation* are hosted and
>> freestanding. A *conforming hosted implementation* shall accept any
>> strictly conforming program. A *conforming freestanding implementation*
>> shall accept any strictly conforming program in which the use of the
>> features specified in the library clause (clause 7) is confined to the
>> contents of the standard headers <float.h>, <iso646.h>, <limits.h>,
>> <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, and
>> <stdnoreturn.h>. A conforming implementation may have extensions
>> (including additional library functions), provided they do not alter
>> the behavior of any strictly conforming program.
>> Basically a hosted implementation is the kind that you're most
>> likely to
>> encounter. It generates code that runs under an operating system, and
>> it supports the entire standard library. A freestanding implementation
>> targets an embedded system that might not have an operating system at
>> all. The only standard library headers that must be supported are the
>> ones that don't declare any functions. A freestanding implementation
>> might provide some library functions, but it isn't required to.
>
> A freestanding implementation might also target the OS itself of a
> common system (not necessarily embedded), right?
Sure. Any implementation that meet's the standard's requirements can be
a conforming freestanding implementation -- even one that targets an OS.
You could call an implementation "freestanding" even if it's just
because you haven't implemented all the required parts of the standard
library.
The standard does have more to say about freestanding implementations
(N1570 5.1.2.1):
In a freestanding environment (in which C program execution
may take place without any benefit of an operating system),
the name and type of the function called at program startup are
implementation-defined. Any library facilities available to a
freestanding program, other than the minimal set required by
clause 4, are implementation-defined.
The effect of program termination in a freestanding environment
is implementation-defined.
And the ANSI C Rationale:
By defining conforming implementations in terms of the programs they
accept, the Standard leaves open the door for a broad class of
extensions as part of a conforming implementation. By defining both
conforming hosted and conforming freestanding implementations, the
Standard recognizes the use of C to write such programs as operating
systems and ROM-based applications, as well as more conventional
hosted applications. Beyond this two-level scheme, no additional
subsetting is defined for C, since the Committee felt strongly that
too many levels dilutes the effectiveness of a standard.
I think the intent is that freestanding implementations are for embedded
systems, likely with no OS, or you're using the implementation to build
the OS, but it's not a strict requirement.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2022-01-30 12:59 -0500 |
| Message-ID | <RlAJJ.23508$1_.9793@fx37.iad> |
| In reply to | #164729 |
On 1/30/22 3:01 AM, Keith Thompson wrote: > Manfred <noname@add.invalid> writes: >> On 1/29/2022 4:37 AM, Keith Thompson wrote: >>> Meredith Montgomery <mmontgomery@levado.to> writes: >>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: >>>>> Meredith Montgomery <mmontgomery@levado.to> writes: >>>>>> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes: >>>>>>> James Kuyper <jameskuyper@alumni.caltech.edu> writes: >>>>>>> [...] >>>>>>>> "... the value is converted by repeatedly adding ... one more than the >>>>>>>> maximum value that can be represented in the new type until the value is >>>>>>>> in the range of the new type." (6.3.1.3p2). >>>>>>>> >>>>>>>> It's the other direction that's dangerous: conversion of an integer >>>>>>>> value to a signed integer type that is not representable in that type >>>>>>>> has undefined behavior. >>>>>>> >>>>>>> No, converting an out-of-range integer value to a signed integer type >>>>>>> yields an implementation-defined result or raises an >>>>>>> implementation-defined signal. (C99 added the option of raising a >>>>>>> signal; in my opinion that was a bad idea.) >>>>>> >>>>>> Just curious --- why do you think a signal is a bad idea? >>>>> >>>>> A signal isn't inherently a bad idea, particularly if portable code can >>>>> handle it. But the fact that the signal is implementation-defined makes >>>>> that impossible. (And freestanding implementations needn't support >>>>> <signal.h>.) >>>> >>>> What's a freestanding implementation? >>> See section 4 of any edition of the C standard. I usually use >>> http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf, a draft >>> that's close to C11. >>> The two forms of *conforming implementation* are hosted and >>> freestanding. A *conforming hosted implementation* shall accept any >>> strictly conforming program. A *conforming freestanding implementation* >>> shall accept any strictly conforming program in which the use of the >>> features specified in the library clause (clause 7) is confined to the >>> contents of the standard headers <float.h>, <iso646.h>, <limits.h>, >>> <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h>, and >>> <stdnoreturn.h>. A conforming implementation may have extensions >>> (including additional library functions), provided they do not alter >>> the behavior of any strictly conforming program. >>> Basically a hosted implementation is the kind that you're most >>> likely to >>> encounter. It generates code that runs under an operating system, and >>> it supports the entire standard library. A freestanding implementation >>> targets an embedded system that might not have an operating system at >>> all. The only standard library headers that must be supported are the >>> ones that don't declare any functions. A freestanding implementation >>> might provide some library functions, but it isn't required to. >> >> A freestanding implementation might also target the OS itself of a >> common system (not necessarily embedded), right? > > Sure. Any implementation that meet's the standard's requirements can be > a conforming freestanding implementation -- even one that targets an OS. > You could call an implementation "freestanding" even if it's just > because you haven't implemented all the required parts of the standard > library. > > The standard does have more to say about freestanding implementations > (N1570 5.1.2.1): > > In a freestanding environment (in which C program execution > may take place without any benefit of an operating system), > the name and type of the function called at program startup are > implementation-defined. Any library facilities available to a > freestanding program, other than the minimal set required by > clause 4, are implementation-defined. > > The effect of program termination in a freestanding environment > is implementation-defined. > > And the ANSI C Rationale: > > By defining conforming implementations in terms of the programs they > accept, the Standard leaves open the door for a broad class of > extensions as part of a conforming implementation. By defining both > conforming hosted and conforming freestanding implementations, the > Standard recognizes the use of C to write such programs as operating > systems and ROM-based applications, as well as more conventional > hosted applications. Beyond this two-level scheme, no additional > subsetting is defined for C, since the Committee felt strongly that > too many levels dilutes the effectiveness of a standard. > > I think the intent is that freestanding implementations are for embedded > systems, likely with no OS, or you're using the implementation to build > the OS, but it's not a strict requirement. > I suppose that means that most 'Windows' implementations are technically 'freestanding' since the program starts at winmain not main (or just not conforming, which also sounds sort of right).
[toc] | [prev] | [next] | [standalone]
| From | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| Date | 2022-01-17 09:41 -0300 |
| Message-ID | <86fspmr0u1.fsf@levado.to> |
| In reply to | #164427 |
James Kuyper <jameskuyper@alumni.caltech.edu> writes: > On 1/15/22 8:14 PM, Meredith Montgomery wrote: >> Bonita Montero <Bonita.Montero@gmail.com> writes: >> >>> Am 03.01.2022 um 18:15 schrieb Meredith Montgomery: >>>> I've seen this somewhere or I wrote this some time in the past for some >>>> reason and I can't see how this make sense any longer. In a procedure >>>> to read a numeric string and turn it into a number, we need to convert >>>> each char-digit to some kind of integer: >>>> (uint64_t) (unsigned char) (s[pos] - '0'); >>> >>> (s[pos] - '0') might me signed and without the cast to unsigned >>> char it might be sign-extended to int64_4 before it is converted >>> to uint64_t. ... > > He's right about it being signed - that's normally the case. It normally > has the type `int`, except in the extremely unlikely case that CHAR_MAX >> INT_MAX, in which case it will have the type `unsigned int`. However, > int64_t comes into play only if it's typedef for `int`. > >>> ... But there are no guarantees when converting negative >>> values to unsigneds. >> >> Really, no guarantees? So a procedure that does > > No, Bonita is mistaken. The standard provides a strong explicit > guarantee of what the behavior is when converting negative values to > unsigned type: > > "... the value is converted by repeatedly adding ... one more than the > maximum value that can be represented in the new type until the value is > in the range of the new type." (6.3.1.3p2). > > It's the other direction that's dangerous: conversion of an integer > value to a signed integer type that is not representable in that type > has undefined behavior. That makes perfect sense. Thanks for the info. Very appreciated.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2022-01-03 14:37 -0500 |
| Message-ID | <0gIAJ.2283$jW.2224@fx05.iad> |
| In reply to | #164237 |
On 1/3/22 12:15 PM, Meredith Montgomery wrote: > I've seen this somewhere or I wrote this some time in the past for some > reason and I can't see how this make sense any longer. In a procedure > to read a numeric string and turn it into a number, we need to convert > each char-digit to some kind of integer: > > (uint64_t) (unsigned char) (s[pos] - '0'); > > But the double cast here seems odd. I could have written this by > copying it from somewhere else. Today, what I would write is just > > (uint64_t) (s[pos] - '0'); > > Am I making a mistake now? I can't anything wrong with this. Isn't a > char just an int? I'm turning an int into an unsigned integer (of a > larger size). > > Thank you! As others have said, it does change the behavior, but only if s[pos] might be less than '0', which means it holds something other than a digit, as the characters 0..9 are a required to be a consecutive increase sequence (which the code is likely counting on). If you know that s[pos] will always be > 0, then the double cast may produce faster code, as unless the compiler can also determine this, it may need to first sign extend to int, then zero extend to uint64_t, verse just zero extending to uint64_t.
[toc] | [prev] | [next] | [standalone]
| From | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| Date | 2022-01-15 22:15 -0300 |
| Message-ID | <86wnj0scpn.fsf@levado.to> |
| In reply to | #164246 |
Richard Damon <Richard@Damon-Family.org> writes: > On 1/3/22 12:15 PM, Meredith Montgomery wrote: >> I've seen this somewhere or I wrote this some time in the past for some >> reason and I can't see how this make sense any longer. In a procedure >> to read a numeric string and turn it into a number, we need to convert >> each char-digit to some kind of integer: >> (uint64_t) (unsigned char) (s[pos] - '0'); >> But the double cast here seems odd. I could have written this by >> copying it from somewhere else. Today, what I would write is just >> (uint64_t) (s[pos] - '0'); >> Am I making a mistake now? I can't anything wrong with this. Isn't >> a >> char just an int? I'm turning an int into an unsigned integer (of a >> larger size). >> Thank you! > > As others have said, it does change the behavior, but only if s[pos] > might be less than '0', which means it holds something other than a > digit, as the characters 0..9 are a required to be a consecutive > increase sequence (which the code is likely counting on). > > If you know that s[pos] will always be > 0, then the double cast may > produce faster code, as unless the compiler can also determine this, > it may need to first sign extend to int, then zero extend to uint64_t, > verse just zero extending to uint64_t. What do you mean by ``zero extend''? Are you qualifying the verb ``to extend''? You lost me there. Thank you.
[toc] | [prev] | [next] | [standalone]
| From | Richard Damon <Richard@Damon-Family.org> |
|---|---|
| Date | 2022-01-15 20:55 -0500 |
| Message-ID | <eWKEJ.204005$Wkjc.110862@fx35.iad> |
| In reply to | #164421 |
On 1/15/22 8:15 PM, Meredith Montgomery wrote: > Richard Damon <Richard@Damon-Family.org> writes: > >> On 1/3/22 12:15 PM, Meredith Montgomery wrote: >>> I've seen this somewhere or I wrote this some time in the past for some >>> reason and I can't see how this make sense any longer. In a procedure >>> to read a numeric string and turn it into a number, we need to convert >>> each char-digit to some kind of integer: >>> (uint64_t) (unsigned char) (s[pos] - '0'); >>> But the double cast here seems odd. I could have written this by >>> copying it from somewhere else. Today, what I would write is just >>> (uint64_t) (s[pos] - '0'); >>> Am I making a mistake now? I can't anything wrong with this. Isn't >>> a >>> char just an int? I'm turning an int into an unsigned integer (of a >>> larger size). >>> Thank you! >> >> As others have said, it does change the behavior, but only if s[pos] >> might be less than '0', which means it holds something other than a >> digit, as the characters 0..9 are a required to be a consecutive >> increase sequence (which the code is likely counting on). >> >> If you know that s[pos] will always be > 0, then the double cast may >> produce faster code, as unless the compiler can also determine this, >> it may need to first sign extend to int, then zero extend to uint64_t, >> verse just zero extending to uint64_t. > > What do you mean by ``zero extend''? Are you qualifying the verb ``to > extend''? You lost me there. Thank you. When the processor loads the 8 bit character into the bottom of the register, it generally leaves the rest of the register alone. If Char is signed, and int is 32 bits, then the implementation can convert it to an int by extending the sign of the bottom byte into the rest of the register, and then to make it a unsigned 54 bit value, it needs to put zeros into the upper 32 bits of the register. By casting to unsigned character, then the implentation only needs to use an instruction that fills the upper 56 bits of the register to 0. Setting the upper bits of a register with a value is called 'extending' If it is copying the sign bit of the lower part of the register, it is called sign extending. If it is just fixing them to zero, it is called zero extending, because we are thinking of the always 0 'sign bits' that extend beyond the bits of the unsigned value.
[toc] | [prev] | [next] | [standalone]
| From | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| Date | 2022-01-17 09:44 -0300 |
| Message-ID | <861r16r0p4.fsf@levado.to> |
| In reply to | #164422 |
Richard Damon <Richard@Damon-Family.org> writes: > On 1/15/22 8:15 PM, Meredith Montgomery wrote: >> Richard Damon <Richard@Damon-Family.org> writes: >> >>> On 1/3/22 12:15 PM, Meredith Montgomery wrote: >>>> I've seen this somewhere or I wrote this some time in the past for some >>>> reason and I can't see how this make sense any longer. In a procedure >>>> to read a numeric string and turn it into a number, we need to convert >>>> each char-digit to some kind of integer: >>>> (uint64_t) (unsigned char) (s[pos] - '0'); >>>> But the double cast here seems odd. I could have written this by >>>> copying it from somewhere else. Today, what I would write is just >>>> (uint64_t) (s[pos] - '0'); >>>> Am I making a mistake now? I can't anything wrong with this. Isn't >>>> a >>>> char just an int? I'm turning an int into an unsigned integer (of a >>>> larger size). >>>> Thank you! >>> >>> As others have said, it does change the behavior, but only if s[pos] >>> might be less than '0', which means it holds something other than a >>> digit, as the characters 0..9 are a required to be a consecutive >>> increase sequence (which the code is likely counting on). >>> >>> If you know that s[pos] will always be > 0, then the double cast may >>> produce faster code, as unless the compiler can also determine this, >>> it may need to first sign extend to int, then zero extend to uint64_t, >>> verse just zero extending to uint64_t. >> What do you mean by ``zero extend''? Are you qualifying the verb >> ``to >> extend''? You lost me there. Thank you. > > When the processor loads the 8 bit character into the bottom of the > register, it generally leaves the rest of the register alone. > > If Char is signed, and int is 32 bits, then the implementation can > convert it to an int by extending the sign of the bottom byte into the > rest of the register, and then to make it a unsigned 54 bit value, it > needs to put zeros into the upper 32 bits of the register. > > By casting to unsigned character, then the implentation only needs to > use an instruction that fills the upper 56 bits of the register to 0. > > Setting the upper bits of a register with a value is called 'extending' > > If it is copying the sign bit of the lower part of the register, it is > called sign extending. > > If it is just fixing them to zero, it is called zero extending, > because we are thinking of the always 0 'sign bits' that extend beyond > the bits of the unsigned value. Awesome information. Thank you so much.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-01-16 05:13 +0100 |
| Message-ID | <ss060d$e1s$1@dont-email.me> |
| In reply to | #164246 |
Am 03.01.2022 um 20:37 schrieb Richard Damon: > If you know that s[pos] will always be > 0, then the double cast may > produce faster code, as unless the compiler can also determine this, > it may need to first sign extend to int, then zero extend to uint64_t, > verse just zero extending to uint64_t. On x86 there are widening-instructions to zero- / sign-extend a shorter value which have all the same performance.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2022-01-15 18:53 -0800 |
| Message-ID | <86y23gtmr0.fsf@linuxsc.com> |
| In reply to | #164237 |
Meredith Montgomery <mmontgomery@levado.to> writes:
> I've seen this somewhere or I wrote this some time in the past for some
> reason and I can't see how this make sense any longer. In a procedure
> to read a numeric string and turn it into a number, we need to convert
> each char-digit to some kind of integer:
>
> (uint64_t) (unsigned char) (s[pos] - '0');
>
> But the double cast here seems odd. I could have written this by
> copying it from somewhere else. Today, what I would write is just
>
> (uint64_t) (s[pos] - '0');
>
> Am I making a mistake now? I can't anything wrong with this. Isn't a
> char just an int? I'm turning an int into an unsigned integer (of a
> larger size).
The original context for the expression in question is this
function:
> [posted by Meredith Montgomery]
>
> #include <limits.h>
> #include <inttypes.h>
>
> int scan_ulong(register char *s, register unsigned long *u)
> {
> register unsigned int pos;
> register unsigned long r;
> register unsigned long c;
>
> pos = 0; r = 0;
>
> for ( ;; ) {
> c = (unsigned long) (unsigned char) (s[pos] - '0');
> if (c < 10) {
> if( ((ULONG_MAX - c) / 10) >= r)
> r = r * 10 + c;
> else return -1; /* lack of space */
> ++pos; continue;
> }
> break;
> }
>
> *u = r;
> return pos;
> }
In this context, the casts are superfluous. Just write
c = s[pos] - '0';
and the right thing will happen, because the assignment to 'c'
converts the value on the right hand side to 'unsigned long',
and so takes care of any negative values.
[toc] | [prev] | [next] | [standalone]
| From | Meredith Montgomery <mmontgomery@levado.to> |
|---|---|
| Date | 2022-01-17 09:46 -0300 |
| Message-ID | <86r196pm0y.fsf@levado.to> |
| In reply to | #164424 |
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Meredith Montgomery <mmontgomery@levado.to> writes:
>
>> I've seen this somewhere or I wrote this some time in the past for some
>> reason and I can't see how this make sense any longer. In a procedure
>> to read a numeric string and turn it into a number, we need to convert
>> each char-digit to some kind of integer:
>>
>> (uint64_t) (unsigned char) (s[pos] - '0');
>>
>> But the double cast here seems odd. I could have written this by
>> copying it from somewhere else. Today, what I would write is just
>>
>> (uint64_t) (s[pos] - '0');
>>
>> Am I making a mistake now? I can't anything wrong with this. Isn't a
>> char just an int? I'm turning an int into an unsigned integer (of a
>> larger size).
>
> The original context for the expression in question is this
> function:
>
>> [posted by Meredith Montgomery]
>>
>> #include <limits.h>
>> #include <inttypes.h>
>>
>> int scan_ulong(register char *s, register unsigned long *u)
>> {
>> register unsigned int pos;
>> register unsigned long r;
>> register unsigned long c;
>>
>> pos = 0; r = 0;
>>
>> for ( ;; ) {
>> c = (unsigned long) (unsigned char) (s[pos] - '0');
>> if (c < 10) {
>> if( ((ULONG_MAX - c) / 10) >= r)
>> r = r * 10 + c;
>> else return -1; /* lack of space */
>> ++pos; continue;
>> }
>> break;
>> }
>>
>> *u = r;
>> return pos;
>> }
>
> In this context, the casts are superfluous. Just write
>
> c = s[pos] - '0';
>
> and the right thing will happen, because the assignment to 'c'
> converts the value on the right hand side to 'unsigned long',
> and so takes care of any negative values.
Oh, interesting! Thanks! I did not think of that.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-01-29 16:57 +0100 |
| Message-ID | <st3o51$jj1$1@dont-email.me> |
| In reply to | #164424 |
Am 16.01.2022 um 03:53 schrieb Tim Rentsch:
> Meredith Montgomery <mmontgomery@levado.to> writes:
>
>> I've seen this somewhere or I wrote this some time in the past for some
>> reason and I can't see how this make sense any longer. In a procedure
>> to read a numeric string and turn it into a number, we need to convert
>> each char-digit to some kind of integer:
>>
>> (uint64_t) (unsigned char) (s[pos] - '0');
>>
>> But the double cast here seems odd. I could have written this by
>> copying it from somewhere else. Today, what I would write is just
>>
>> (uint64_t) (s[pos] - '0');
>>
>> Am I making a mistake now? I can't anything wrong with this. Isn't a
>> char just an int? I'm turning an int into an unsigned integer (of a
>> larger size).
>
> The original context for the expression in question is this
> function:
>
>> [posted by Meredith Montgomery]
>>
>> #include <limits.h>
>> #include <inttypes.h>
>>
>> int scan_ulong(register char *s, register unsigned long *u)
>> {
>> register unsigned int pos;
>> register unsigned long r;
>> register unsigned long c;
>>
>> pos = 0; r = 0;
>>
>> for ( ;; ) {
>> c = (unsigned long) (unsigned char) (s[pos] - '0');
>> if (c < 10) {
>> if( ((ULONG_MAX - c) / 10) >= r)
>> r = r * 10 + c;
>> else return -1; /* lack of space */
>> ++pos; continue;
>> }
>> break;
>> }
>>
>> *u = r;
>> return pos;
>> }
>
> In this context, the casts are superfluous. Just write
>
> c = s[pos] - '0';
This makes different results if "s[pos] - '0'" is negative.
>
> and the right thing will happen, because the assignment to 'c'
> converts the value on the right hand side to 'unsigned long',
> and so takes care of any negative values.
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-01-29 09:54 -0800 |
| Message-ID | <09fcd422-c929-4c5b-a15a-099bbe4a8e81n@googlegroups.com> |
| In reply to | #164718 |
On Saturday, 29 January 2022 at 17:57:34 UTC+2, Bonita Montero wrote:
> Am 16.01.2022 um 03:53 schrieb Tim Rentsch:
> > Meredith Montgomery <mmont...@levado.to> writes:
> >
> >> I've seen this somewhere or I wrote this some time in the past for some
> >> reason and I can't see how this make sense any longer. In a procedure
> >> to read a numeric string and turn it into a number, we need to convert
> >> each char-digit to some kind of integer:
> >>
> >> (uint64_t) (unsigned char) (s[pos] - '0');
> >>
> >> But the double cast here seems odd. I could have written this by
> >> copying it from somewhere else. Today, what I would write is just
> >>
> >> (uint64_t) (s[pos] - '0');
> >>
> >> Am I making a mistake now? I can't anything wrong with this. Isn't a
> >> char just an int? I'm turning an int into an unsigned integer (of a
> >> larger size).
> >
> > The original context for the expression in question is this
> > function:
> >
> >> [posted by Meredith Montgomery]
> >>
> >> #include <limits.h>
> >> #include <inttypes.h>
> >>
> >> int scan_ulong(register char *s, register unsigned long *u)
> >> {
> >> register unsigned int pos;
> >> register unsigned long r;
> >> register unsigned long c;
> >>
> >> pos = 0; r = 0;
> >>
> >> for ( ;; ) {
> >> c = (unsigned long) (unsigned char) (s[pos] - '0');
> >> if (c < 10) {
> >> if( ((ULONG_MAX - c) / 10) >= r)
> >> r = r * 10 + c;
> >> else return -1; /* lack of space */
> >> ++pos; continue;
> >> }
> >> break;
> >> }
> >>
> >> *u = r;
> >> return pos;
> >> }
> >
> > In this context, the casts are superfluous. Just write
> >
> > c = s[pos] - '0';
> This makes different results if "s[pos] - '0'" is negative.
Your usual incapability to read next sentence below that addresses it
specifically noted.
> >
> > and the right thing will happen, because the assignment to 'c'
> > converts the value on the right hand side to 'unsigned long',
> > and so takes care of any negative values.
Works, unlike your pathetically borken functions in another thread:
https://groups.google.com/g/comp.lang.c/c/pfgpeqAm0h8/m/y9MHNBwuAQAJ
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2022-01-30 13:17 +0100 |
| Message-ID | <st5vkl$o02$1@dont-email.me> |
| In reply to | #164720 |
Am 29.01.2022 um 18:54 schrieb Öö Tiib:
> On Saturday, 29 January 2022 at 17:57:34 UTC+2, Bonita Montero wrote:
>> Am 16.01.2022 um 03:53 schrieb Tim Rentsch:
>>> Meredith Montgomery <mmont...@levado.to> writes:
>>>
>>>> I've seen this somewhere or I wrote this some time in the past for some
>>>> reason and I can't see how this make sense any longer. In a procedure
>>>> to read a numeric string and turn it into a number, we need to convert
>>>> each char-digit to some kind of integer:
>>>>
>>>> (uint64_t) (unsigned char) (s[pos] - '0');
>>>>
>>>> But the double cast here seems odd. I could have written this by
>>>> copying it from somewhere else. Today, what I would write is just
>>>>
>>>> (uint64_t) (s[pos] - '0');
>>>>
>>>> Am I making a mistake now? I can't anything wrong with this. Isn't a
>>>> char just an int? I'm turning an int into an unsigned integer (of a
>>>> larger size).
>>>
>>> The original context for the expression in question is this
>>> function:
>>>
>>>> [posted by Meredith Montgomery]
>>>>
>>>> #include <limits.h>
>>>> #include <inttypes.h>
>>>>
>>>> int scan_ulong(register char *s, register unsigned long *u)
>>>> {
>>>> register unsigned int pos;
>>>> register unsigned long r;
>>>> register unsigned long c;
>>>>
>>>> pos = 0; r = 0;
>>>>
>>>> for ( ;; ) {
>>>> c = (unsigned long) (unsigned char) (s[pos] - '0');
>>>> if (c < 10) {
>>>> if( ((ULONG_MAX - c) / 10) >= r)
>>>> r = r * 10 + c;
>>>> else return -1; /* lack of space */
>>>> ++pos; continue;
>>>> }
>>>> break;
>>>> }
>>>>
>>>> *u = r;
>>>> return pos;
>>>> }
>>>
>>> In this context, the casts are superfluous. Just write
>>>
>>> c = s[pos] - '0';
>> This makes different results if "s[pos] - '0'" is negative.
>
> Your usual incapability to read next sentence below that addresses it
> specifically noted.
>
>>>
>>> and the right thing will happen, because the assignment to 'c'
>>> converts the value on the right hand side to 'unsigned long',
>>> and so takes care of any negative values.
That's not true. The compiler may give a negative value
converted to an unsigned value:
__declspec(noinline)
unsigned long f( char c )
{
return c - '0';
}
movsx eax, cl
sub eax, 48
ret 0
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2022-01-30 23:53 -0800 |
| Message-ID | <1e8187ef-8fa7-4439-aae7-8ad8d1e1a9f6n@googlegroups.com> |
| In reply to | #164731 |
On Sunday, 30 January 2022 at 14:17:37 UTC+2, Bonita Montero wrote:
> Am 29.01.2022 um 18:54 schrieb Öö Tiib:
> > On Saturday, 29 January 2022 at 17:57:34 UTC+2, Bonita Montero wrote:
> >> Am 16.01.2022 um 03:53 schrieb Tim Rentsch:
> >>> Meredith Montgomery <mmont...@levado.to> writes:
> >>>
> >>>> I've seen this somewhere or I wrote this some time in the past for some
> >>>> reason and I can't see how this make sense any longer. In a procedure
> >>>> to read a numeric string and turn it into a number, we need to convert
> >>>> each char-digit to some kind of integer:
> >>>>
> >>>> (uint64_t) (unsigned char) (s[pos] - '0');
> >>>>
> >>>> But the double cast here seems odd. I could have written this by
> >>>> copying it from somewhere else. Today, what I would write is just
> >>>>
> >>>> (uint64_t) (s[pos] - '0');
> >>>>
> >>>> Am I making a mistake now? I can't anything wrong with this. Isn't a
> >>>> char just an int? I'm turning an int into an unsigned integer (of a
> >>>> larger size).
> >>>
> >>> The original context for the expression in question is this
> >>> function:
> >>>
> >>>> [posted by Meredith Montgomery]
> >>>>
> >>>> #include <limits.h>
> >>>> #include <inttypes.h>
> >>>>
> >>>> int scan_ulong(register char *s, register unsigned long *u)
> >>>> {
> >>>> register unsigned int pos;
> >>>> register unsigned long r;
> >>>> register unsigned long c;
> >>>>
> >>>> pos = 0; r = 0;
> >>>>
> >>>> for ( ;; ) {
> >>>> c = (unsigned long) (unsigned char) (s[pos] - '0');
> >>>> if (c < 10) {
> >>>> if( ((ULONG_MAX - c) / 10) >= r)
> >>>> r = r * 10 + c;
> >>>> else return -1; /* lack of space */
> >>>> ++pos; continue;
> >>>> }
> >>>> break;
> >>>> }
> >>>>
> >>>> *u = r;
> >>>> return pos;
> >>>> }
> >>>
> >>> In this context, the casts are superfluous. Just write
> >>>
> >>> c = s[pos] - '0';
> >> This makes different results if "s[pos] - '0'" is negative.
> >
> > Your usual incapability to read next sentence below that addresses it
> > specifically noted.
> >
> >>>
> >>> and the right thing will happen, because the assignment to 'c'
> >>> converts the value on the right hand side to 'unsigned long',
> >>> and so takes care of any negative values.
>
> That's not true. The compiler may give a negative value
> converted to an unsigned value:
>
> __declspec(noinline)
> unsigned long f( char c )
> {
> return c - '0';
> }
>
> movsx eax, cl
> sub eax, 48
> ret 0
And little negative value converted to unsigned value does not
satisfy < 10. Works, unlike your pathetically borken functions
in another thread:
https://groups.google.com/g/comp.lang.c/c/pfgpeqAm0h8/m/y9MHNBwuAQAJ
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.c
csiph-web