Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #400270 > unrolled thread

Representing signed values in corresponding unsigned types

Started byNS <ns@2b.here>
First post2026-06-28 10:11 +0000
Last post2026-06-28 20:24 -0700
Articles 9 — 6 participants

Back to article view | Back to comp.lang.c


Contents

  Representing signed values in corresponding unsigned types NS <ns@2b.here> - 2026-06-28 10:11 +0000
    Re: Representing signed values in corresponding unsigned types ram@zedat.fu-berlin.de (Stefan Ram) - 2026-06-28 12:07 +0000
    Re: Representing signed values in corresponding unsigned types Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-06-28 06:52 -0700
      Re: Representing signed values in corresponding unsigned types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-28 18:27 -0700
        Re: Representing signed values in corresponding unsigned types cross@spitfire.i.gajendra.net (Dan Cross) - 2026-06-29 12:13 +0000
        Re: Representing signed values in corresponding unsigned types Tim Rentsch <tr.17687@z991.linuxsc.com> - 2026-08-15 02:19 -0700
          Re: Representing signed values in corresponding unsigned types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-08-15 05:48 -0700
    Re: Representing signed values in corresponding unsigned types James Kuyper <jameskuyper@alumni.caltech.edu> - 2026-06-28 22:23 -0400
      Re: Representing signed values in corresponding unsigned types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2026-06-28 20:24 -0700

#400270 — Representing signed values in corresponding unsigned types

FromNS <ns@2b.here>
Date2026-06-28 10:11 +0000
SubjectRepresenting signed values in corresponding unsigned types
Message-ID<111qs0g$3hdko$1@dont-email.me>
Can all the values of a signed int be represented in an unsigned int (or 
signed long in an unsigned long, etc.)? If INT_MIN is now 0 and all values are
arithmetically increased by -INT_MIN, is it guaranteed that every signed
value can be represented? In other words: is UINT_MAX >= INT_MAX - INT_MIN?

It seems obvious, but the standard appears to imply that this is not
guaranteed. It states:

>6.2.5.6
>
>For each of the signed integer types, there is a corresponding (but
>different) unsigned integer type that uses the same amount of storage 
>(including sign information) and has the same alignment requirements.

So, same amount of storage including sign bit implies UINT_MAX == INT_MAX*2

But:

>6.2.6.2
>
>For unsigned integer types, the bits of the object representation shall be
>divided into two groups: value bits and padding bits.
>[...]
>For signed integer types, the bits of an object representation shall be
>divided into three groups: value bits, padding bits and the sign bit. [...]
>(if there are M value bits in the signed type and N in the unsigned type,
>then M <= N).

But shouldn't it be M < N? Otherwise, if M == N, there are the same amount of
value bits in both signed and unsigned (implying the unsigned has more
padding bits), and UINT_MAX == INT_MAX. I doubt that this is ever done,
but the standard seems to permit it.

Although "The range of nonnegative values of a signed integer type is a 
subrange of its corresponding unsigned integer type" [6.2.5.9] the use of
'subrange' implies that M < N?


So, is it actually portable to represent signed integers as unsigned?

[toc] | [next] | [standalone]


#400271

Fromram@zedat.fu-berlin.de (Stefan Ram)
Date2026-06-28 12:07 +0000
Message-ID<range-20260628130625@ram.dialup.fu-berlin.de>
In reply to#400270
NS <ns@2b.here> wrote or quoted:
>Although "The range of nonnegative values of a signed integer type is a 
>subrange of its corresponding unsigned integer type" [6.2.5.9] the use of
>'subrange' implies that M < N?

  I take a "subrange" to be a range that is a subset, 
  which would imply M <= N.

[toc] | [prev] | [next] | [standalone]


#400272

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-06-28 06:52 -0700
Message-ID<86zf0e7ox4.fsf@linuxsc.com>
In reply to#400270
NS <ns@2b.here> writes:

> Can all the values of a signed int be represented in an unsigned
> int (or signed long in an unsigned long, etc.)?

Not guaranteed.

> If INT_MIN is now 0 and
> all values are arithmetically increased by -INT_MIN, is it
> guaranteed that every signed value can be represented?

No.

> In other words:  is UINT_MAX >= INT_MAX - INT_MIN?

Not guaranteed.  The case of UINT_MAX == INT_MAX is allowed.

> It seems obvious, but the standard appears to imply that this is
> not guaranteed.  It states:

The standard allows implementations where UINT_MAX == INT_MAX.

>> 6.2.5.6
>>
>> For each of the signed integer types, there is a corresponding (but
>> different) unsigned integer type that uses the same amount of storage
>> (including sign information) and has the same alignment requirements.
>
> So, same amount of storage including sign bit implies
> UINT_MAX == INT_MAX*2

It doesn't, because integer types (other than unsigned char) are
allowed to have padding bits, and unsigned types may have more
padding bits than signed types have.

> But:
>
>> 6.2.6.2
>>
>> For unsigned integer types, the bits of the object representation
>> shall be divided into two groups:  value bits and padding bits.
>> [...]

>> For signed integer types, the bits of an object representation
>> shall be divided into three groups:  value bits, padding bits and
>> the sign bit.  [...]  (if there are M value bits in the signed type
>> and N in the unsigned type, then M <= N).
>
> But shouldn't it be M < N?

The standard means what it says.  The case of M == N is allowed.

> Otherwise, if M == N, there are the same
> amount of value bits in both signed and unsigned (implying the
> unsigned has more padding bits), and UINT_MAX == INT_MAX.

That's right.

> I doubt that this is ever done,

It has been.

> but the standard seems to permit it.

Yes, deliberately so.

> Although "The range of nonnegative values of a signed integer type
> is a subrange of its corresponding unsigned integer type" [6.2.5.9]
> the use of 'subrange' implies that M < N?

Normal usage for "subrange" includes the case where the two ranges
are the same.

> So, is it actually portable to represent signed integers as
> unsigned?

Not fully portable, no.  If it's important that this be true then
somewhere there should be a test that INT_MAX < UINT_MAX, etc.

(Note that as of C23 there are different rules, and indeed the newer
standard requires, IIUC, that unsigned types have the same number of
padding bits as their corresponding signed types, and consequently
that INT_MAX < UINT_MAX, etc.)

[toc] | [prev] | [next] | [standalone]


#400277

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-06-28 18:27 -0700
Message-ID<111shlo$3vq40$2@kst.eternal-september.org>
In reply to#400272
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> NS <ns@2b.here> writes:
>> Can all the values of a signed int be represented in an unsigned
>> int (or signed long in an unsigned long, etc.)?

Obviously not.  Negative values cannot be represented in unsigned types.
But I don't think that's what NS meant.

I believe it follows from the *current* rules (C23) that the number
of representable values in signed int is exactly the same as the
number of representable values in unsigned int.  It also follows
that each possible value of type signed int yields a unique value
when converted to unsigned int.  (The reverse conversion is still
implementation-defined.)

That wasn't the case in C17 and earlier.  It was allowed, for
example, for signed int and unsigned int to have the same size,
with signed int having no padding bits and unsigned int having one
(in place of the sign bit).  Thus you could have INT_MAX==UINT_MAX.

Such implementations were quite unusual, which presumably is why the
committee was able to make them non-conforming in C23.

[...]

> It doesn't, because integer types (other than unsigned char) are
> allowed to have padding bits, and unsigned types may have more
> padding bits than signed types have.

Neither unsigned char nor signed char is allowed to have padding
bits, going back at least to C99.  (I believe C99 is when the concept
of padding bits was introduced.)  This implies that plain char also
is not allowed to have padding bits)

[...]

>> So, is it actually portable to represent signed integers as
>> unsigned?
>
> Not fully portable, no.  If it's important that this be true then
> somewhere there should be a test that INT_MAX < UINT_MAX, etc.
>
> (Note that as of C23 there are different rules, and indeed the newer
> standard requires, IIUC, that unsigned types have the same number of
> padding bits as their corresponding signed types, and consequently
> that INT_MAX < UINT_MAX, etc.)

Note that C23 is the current ISO C standard, and C23 with extensions
is the default dialect for recent releases of gcc and clang.

Of course earlier editions are still relevant.

I believe you're correct about the change in requirements
for C23.  Most obviously, C23 requires 2's-complement for all
signed types (prior editions also allowed sign-and-magnitude and
ones'-complement).

N3220 6.2.6.2p2 says:

    For signed integer types, the bits of the object representation
    shall be divided into three groups: value bits, padding bits,
    and the sign bit. If the corresponding unsigned type has width
    N, the signed type uses the same number of N bits, its *width*,
    as value bits and sign bit.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#400283

Fromcross@spitfire.i.gajendra.net (Dan Cross)
Date2026-06-29 12:13 +0000
Message-ID<111tngq$ned$1@reader1.panix.com>
In reply to#400277
In article <111shlo$3vq40$2@kst.eternal-september.org>,
Keith Thompson  <Keith.S.Thompson+u@gmail.com> wrote:
>Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>> NS <ns@2b.here> writes:
>>> Can all the values of a signed int be represented in an unsigned
>>> int (or signed long in an unsigned long, etc.)?
>
>Obviously not.  Negative values cannot be represented in unsigned types.
>But I don't think that's what NS meant.

Agreed.  I believe NS's question could be rephrased as, "does
the standard guarantee that there is an injection from values of
type signed int to values of unsigned int?"

	- Dan C.

[toc] | [prev] | [next] | [standalone]


#401204

FromTim Rentsch <tr.17687@z991.linuxsc.com>
Date2026-08-15 02:19 -0700
Message-ID<86fr0f68rr.fsf@linuxsc.com>
In reply to#400277
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>
>> NS <ns@2b.here> writes:
>>
>>> Can all the values of a signed int be represented in an unsigned
>>> int (or signed long in an unsigned long, etc.)?
>
> Obviously not.  Negative values cannot be represented in unsigned
> types.  But I don't think that's what NS meant.

The question is Can all the values of a signed int be represented in
an unsigned int?  The question is not can an unsigned int hold all
the values of a signed int.  An apple, an orange, and a banana can
represent the integers 1, 2, and 3.  All the values of a signed
int can be represented in an unsigned int, as long as UINT_MAX is
greater than INT_MAX.

[toc] | [prev] | [next] | [standalone]


#401207

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-08-15 05:48 -0700
Message-ID<115pn7p$3c96f$2@kst.eternal-september.org>
In reply to#401204
Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
> Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
>> Tim Rentsch <tr.17687@z991.linuxsc.com> writes:
>>> NS <ns@2b.here> writes:
>>>
>>>> Can all the values of a signed int be represented in an unsigned
>>>> int (or signed long in an unsigned long, etc.)?
>>
>> Obviously not.  Negative values cannot be represented in unsigned
>> types.  But I don't think that's what NS meant.
>
> The question is Can all the values of a signed int be represented in
> an unsigned int?  The question is not can an unsigned int hold all
> the values of a signed int.  An apple, an orange, and a banana can
> represent the integers 1, 2, and 3.  All the values of a signed
> int can be represented in an unsigned int, as long as UINT_MAX is
> greater than INT_MAX.

I already covered this nearly two months ago, in text that you
snipped in your followup.

Some of the values of a signed int are negative.  Negative values
cannot be represented in an unsigned int.  Or are you saying that the
siged int value -1 can "represent" the unsigned int value UINT_MAX?
That's not what "represent" means.

C currently requires UINT_MAX to be greater than INT_MAX; this is
new in C23 -- something I also mentioned previously.

If you're going to wait months before posting a followup, please
retain more context.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#400279

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2026-06-28 22:23 -0400
Message-ID<111sku4$3vcj4$1@dont-email.me>
In reply to#400270
On 2026-06-28 06:11, NS wrote:
> Can all the values of a signed int be represented in an unsigned int (or 
> signed long in an unsigned long, etc.)?

Of course not. Signed int can represent negative values, unsigned int
cannot.

However, "The range of nonnegative values of a signed integer type is a
subrange of the corresponding unsigned integer type, and the
representation of the same value in each type is the same."(6.2.5p11)

I see that you've quoted this same clause below, but cut off the
citation just before it provided the fullest possible answer to your
first question above.

...
>> 6.2.5.6
>>
>> For each of the signed integer types, there is a corresponding (but
>> different) unsigned integer type that uses the same amount of storage 
>> (including sign information) and has the same alignment requirements.
> 
> So, same amount of storage including sign bit implies UINT_MAX == INT_MAX*2

No, first of all, the same amount of storage does not require that the
number of bits be the same. secondly, if the number of bits were the
same, then the relationship would be UINT_MAX == INT_MAX*2U+1U. The U's
ensure that the calculations are carried out using unsigned int;
otherwise the expression would produce unsigned overflow.

...
>> 6.2.6.2
>>
>> For unsigned integer types, the bits of the object representation shall be
>> divided into two groups: value bits and padding bits.
>> [...]
>> For signed integer types, the bits of an object representation shall be
>> divided into three groups: value bits, padding bits and the sign bit. [...]
>> (if there are M value bits in the signed type and N in the unsigned type,
>> then M <= N).
> 
> But shouldn't it be M < N? Otherwise, if M == N, there are the same amount of
> value bits in both signed and unsigned (implying the unsigned has more
> padding bits), and UINT_MAX == INT_MAX. I doubt that this is ever done,
> but the standard seems to permit it.

It does.
I've heard of a system which did not have an arithmetic unit, but did
have a floating point unit, which used the mantissa of floating point
values to represent a large integer type. I think they would have had
INT_MAX == UINT_MAX, but I can't vouch for that personally.

> Although "The range of nonnegative values of a signed integer type is a 
> subrange of its corresponding unsigned integer type" [6.2.5.9] the use of
> 'subrange' implies that M < N?
You're thinking of a "proper subrange", by analogy with the term "proper
subset", but the standard does not require that the subrange be proper.

[toc] | [prev] | [next] | [standalone]


#400281

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2026-06-28 20:24 -0700
Message-ID<111soh4$1eq8$2@kst.eternal-september.org>
In reply to#400279
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
> On 2026-06-28 06:11, NS wrote:
[...]
>> But shouldn't it be M < N? Otherwise, if M == N, there are the same amount of
>> value bits in both signed and unsigned (implying the unsigned has more
>> padding bits), and UINT_MAX == INT_MAX. I doubt that this is ever done,
>> but the standard seems to permit it.
>
> It does.
> I've heard of a system which did not have an arithmetic unit, but did
> have a floating point unit, which used the mantissa of floating point
> values to represent a large integer type. I think they would have had
> INT_MAX == UINT_MAX, but I can't vouch for that personally.

That's allowed in C17 and earlier, but not (I think) in C23.  Though
it's possible that I'm misinterpreting the C23 wording (which I've
quoted elsethread).

[...]

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web