Sizes of Integer Types

I

Ian Collins

Kelsey said:
Indeed. And yet you can't rely on that, because the new int types may not
exist *at all* on the new platform.

Then you either add them, or give up as you can't port the code.
 
I

Ian Collins

Kelsey said:
[snips]

You're still missing the point. If I want to write code that is only
portable to systems that have a 32-bit integer type, then the easiest
way to get that data type is to use int32_t.


Which deals with one type. You can, of course, guarantee that this system
_also_ has, oh, 8 bit integer types, right? No? So all that code using
uint8_t now has to be scrapped or rewritten, because the types simply
aren't available.

By the time you get to the point where all these new types make sense,
you've essentially restricted C to existing only on 32-bit x86 machines or
close equivalents. Hardly sensible.

Nonsense, I wouldn't call PPC or SPARC "close equivalents" to x86.
Nor can you rely on the new types, as they may well simply not exist on
a given implementation. Yes, and?

If your code requires exact size types that can't be defined for a
particular system, it can't be run on that system without rework,
whether the typedefs exist or not.
 
R

Richard Heathfield

Ian Collins said:
Then you either add them, or give up as you can't port the code.

No, you write the code so as not to need them. In other words, you write
your code *not* to rely on exact size.

Kelsey is absolutely right. If a type isn't guaranteed to be provided by
the implementation, one cannot use it in code that is required to be
portable to arbitrary implementations.
 
I

Ian Collins

Richard said:
Ian Collins said:


No, you write the code so as not to need them. In other words, you write
your code *not* to rely on exact size.

Kelsey is absolutely right. If a type isn't guaranteed to be provided by
the implementation, one cannot use it in code that is required to be
portable to arbitrary implementations.
Then you have the concept of standard conforming, non-portable code.

Sometimes you do have to either rely on a fixed size, or go through a
more convoluted process to work round the possibility of that size not
being available.
 
R

Richard Heathfield

Ian Collins said:
Richard Heathfield wrote:

Then you have the concept of standard conforming, non-portable code.

Yes, of course. C99 makes it not only possible but easy to write such
code. Not only does the use of C99 features render your code
non-portable to C90 implementations, but it can even render your code
non-portable to *other C99 implementations*.

This is true of C90, too, but in a much more limited way. For example, I
have occasionally had cause to define an array of UCHAR_MAX + 1
unsigned long ints, which seems perfectly unobjectionable and indeed is
quite okay on what you might call "normal" implementations - but on
reflection it's easy to see how it could break. If CHAR_BIT is 32, say,
then that array is suddenly rather on the large side.

So one must exercise care even in C90 (or accept that one's code is not
portable to certain kinds of implementation). C99 has all of the C90
portability issues, and adds a whole bunch of new ones.
 
I

Ian Collins

Richard said:
So one must exercise care even in C90 (or accept that one's code is not
portable to certain kinds of implementation). C99 has all of the C90
portability issues, and adds a whole bunch of new ones.
But availability of fixed with types isn't one of them, it has always
been an issue. All C99 does is provide a standardised set of names.

If your code is processing a stream of say 16 bit data, you can either
assume the existence of a 16 (or 8) bit type, or come up with something
horribly complex to cope with systems where integer types are a multiple
of something other than eight.
 
C

Charlie Gordon

Al Balmer said:
They are not guaranteed to be the same size on different platforms,
and sometimes you want exact size.

More precisely, int32_t is guaranteed to use 2's complement and no padding
with exactly 32 bits. Such is not the case of int_least32_t that can use
another arithmetic model. The minimal range of values supported by
int_least32_t is not superset of that of int32_t, which is fixed and
specified.

int32_t warrants exact size _and_ arithmetic model.
 
R

Richard Heathfield

Ian Collins said:
Richard said:
So one must exercise care even in C90 (or accept that one's code is
not portable to certain kinds of implementation). C99 has all of the
C90 portability issues, and adds a whole bunch of new ones.
But availability of fixed wi[d]th types isn't one of them,

It *is*, if people are lured into using C99's named types unnecessarily,
because they (erroneously) believe that this somehow makes their code
more portable than is in fact the case.
it has always been an issue.

....but not a huge one - certainly not huge enough to justify C99's
muddying the waters of portability.
All C99 does is provide a standardised set of names.

....which don't actually perform any useful function that I can see.
If your code is processing a stream of say 16 bit data, you can either
assume the existence of a 16 (or 8) bit type, or come up with
something horribly complex to cope with systems where integer types
are a multiple of something other than eight.

Indeed. The first choice is a natural one, but has its limitations, as
we have already seen. The second choice is a harder road, but it is
unavoidable if maximal portability is a prerequisite.
 
P

Philip Potter

Kelsey said:
[snips]

This newsgroup notwithstanding, the reality is that there are a lot of
people that choose to write "unportable" code for various purposes.

Sure, I've done so myself. And when doing so, I'll happily use the fact
that on implementation X, char is 8 bits, int 16, long 32 or what have you
and not need those pesky int32_t things at all.

Remember, they have to exist _if_ the implementation already has such
types, meaning that if they exist, you *already* have perfectly
functional, though non-portable, options, making the int types completely
irrelevant.

Consider the following two implementations:

Integer type | SizeA | SizeB
char | 8 | 8
short | 16 | 16
int | 32 | 16
long | 64 | 32

Both implementations have a 32-bit integer type, but they're called different
things. Using int32_t does all the pesky #ifdefing for you.
 
A

Army1987

Personally I think it would be better if it required providing the
intN_t types for all values of N for which it has a type with no
padding bits (and two's complement for the signed versions). I can't see
that it would be much work for the implementer.


Such a requirement has been added in n1124:
These types are optional. However, if an implementation provides integer types with
widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a
two’s complement representation, it shall deï¬ne the corresponding typedef names.
 
A

Army1987

Their unportability is, in this case, a feature. Suppose that you want
an exactly 32-bit unsigned type, for example to agree with a file
format.
How do you know that your type has the same endianness as the file
format?
If your C99 implementation has a type of the kind you want, you
can rely on uint32_t being there. If uint32_t is not available, that
implementation is simply never going to give you what you want. In C90,
you'd have to put that kind of type behind conditional compilation
#ifdefs, one for each platform you want, _and_ hope that your compiler
never introduces padding bits behind your back; or you have to surround
every use of your type with &0xFFFFFFFF and so on. In C99, all you have
to do is check whether your compiler complains about uint32_t not
existing.

(Or more sanely
#ifndef UINT32_MAX
#error something
#endif
)
 
R

Richard Bos

Kelsey Bjarnason said:
[snips]

On Tue, 11 Sep 2007 12:08:08 +0000, Richard Bos wrote:

Their unportability is, in this case, a feature. Suppose that you want
an exactly 32-bit unsigned type, for example to agree with a file
format. If your C99 implementation has a type of the kind you want, you
can rely on uint32_t being there. If uint32_t is not available, that
implementation is simply never going to give you what you want.

No, but if I were to use, say, an unsigned long I'd know I was using an
unsigned type at least 32 bits long, and more importantly, I'd know the
type was going to exist, period.

So now I use a uint32_t and my code fails on compiler X because the type
simply does not exist.

Then, neither does the 32-bit unsigned long. If your requirement is
for a type *at least* 32 bits, rather than exactly 32 bits, you would
use int_least32_t.

Exactly the point. We *already* have, without the new int types, a
functional set of types which are _at least_ n bits wide.

Yes. And _exactly_ n bits wide?
They have all the utility of void main() - they'll work, somewhere, on some
compiler, for some definition of "work", but you can't rely on them
working _at all_ on an arbitrary compiler.

void main() adds no functionality. Exact-width types do.

Richard
 
R

Richard Bos

CBFalconer said:
Richard said:
CBFalconer said:
Flash Gordon wrote:

Personally I think it would be better if it required providing the
intN_t types for all values of N for which it has a type with
no padding bits (and two's complement for the signed versions). I
can't see that it would be much work for the implementer.

Ugh. You don't really want to hear my opinion about those useless
non-portable foolishnesses.


Their unportability is, in this case, a feature. Suppose that you want
an exactly 32-bit unsigned type, for example to agree with a file
format. If your C99 implementation has a type of the kind you want, you
can rely on uint32_t being there. If uint32_t is not available, that
implementation is simply never going to give you what you want. In C90,
you'd have to put that kind of type behind conditional compilation
#ifdefs, one for each platform you want, _and_ hope that your compiler
never introduces padding bits behind your back; or you have to surround
every use of your type with &0xFFFFFFFF and so on. In C99, all you have
to do is check whether your compiler complains about uint32_t not
existing.


Lets work with your example. The padding bits don't matter,
because they don't show up in the actual values, they are limited
to catching such things as use of uninitialized data, or ECC error
correction, etc. So we assume the file system is capable of
writing 36 bit values, as a result of having CHAR_BIT == 9 in the
system. But you are writing software using values that have to
work on the usual system with CHAR_BIT == 8. unsigned long always
has at least 32 bits available, so you use that type (or
uint32_t). The padding doesn't matter, as stated above (most
systems with ECC today really have a 72 bit word, which is what is
really being read and written from/to memory).

You have less worries about overflows with the 36 bit system.
Using unsigned values, truncation down to 32 bits doesn't matter,
the truncated result will be identical to the value on the 32 bit
system. But it is generally easier to detect 32 bit overflow with
a 36 bit system. You won't be doing any such.

What you will be doing is reading and writing those values to the
file or i/o system. If the peripheral or file only handles 32 bit
wide values, it will just ignore the higher order bits. This just
gives the identical result to what would have happened on the 32
bit system. Everything is free!!.

What about input from the device/file? The high order bits will be
zeroed, we assume, because the hardware has some pins tied to
ground, or the equivalent. In comes a value identical the the
value on the 32 bit system. Once more, everything is free.

Notice there has never been any need to mask off fields. Now shoot
me down.


Predictable PRNGs.
*BANG*

Cyclic counters, parallel, synchonisation of.
*BANG*

Want me to go on shooting?

Fix yer sig.

Richard
 
C

Chris Hills

Kelsey Bjarnason said:
[snips]

If you just want integer types of specified sizes, take a look at the
<stdint.h> header, which defines int8_t, int16_t, etc.

My copy of the draft says
Your copy of the draft is irrelevant.

It is a DRAFT if you are going to mess around with the compiler you need
the standard itself. NOT a draft.
 
R

Richard Bos

Kelsey Bjarnason said:
Indeed. And yet you can't rely on that, because the new int types may not
exist *at all* on the new platform.

In which case, the program you want can't be easily written for that
platform anyway. So instead of hacking your way around with bitwise
operations and getting files that may or may not work depending on your
file transfer settings, you accept that you don't want to use that
platform. _Or_ you choose the pain. But at least you're pre-warned.

Richard
 
R

Richard Heathfield

Chris Hills said:
Kelsey Bjarnason said:
[snips]

If you just want integer types of specified sizes, take a look at
the <stdint.h> header, which defines int8_t, int16_t, etc.

My copy of the draft says
Your copy of the draft is irrelevant.

It is a DRAFT if you are going to mess around with the compiler you
need the standard itself. NOT a draft.

Is it your contention that the final Standard differs from the draft in
this regard? Specifically, Kelsey said: "My copy of the draft says that
intN_t types are optional, an implementation is not required to provide
them." As far as I'm aware, this remains true in the final Standard. I
refer you specifically to 7.18(4): "An implementation shall provide
those types described as ``required'', but need not provide any of the
others (described as ``optional'')."

It seems to me that your objection is nebulous.
 
C

Chris Hills

Richard Heathfield said:
Chris Hills said:
Kelsey Bjarnason said:
[snips]

On Thu, 06 Sep 2007 11:51:57 -0700, Keith Thompson wrote:

If you just want integer types of specified sizes, take a look at
the <stdint.h> header, which defines int8_t, int16_t, etc.

My copy of the draft says
Your copy of the draft is irrelevant.

It is a DRAFT if you are going to mess around with the compiler you
need the standard itself. NOT a draft.

Is it your contention that the final Standard differs from the draft in
this regard?

No. Just that the draft is just that and there are changes between the
draft and the standard. When you are quoting chapter and verse anything
other than the standard has no validity.
Specifically, Kelsey said: "My copy of the draft says that
intN_t types are optional, an implementation is not required to provide
them." As far as I'm aware,

So you are not certain then?
this remains true in the final Standard. I
refer you specifically to 7.18(4): "An implementation shall provide
those types described as ``required'', but need not provide any of the
others (described as ``optional'')."

It seems to me that your objection is nebulous.

So it's ok to quote chapter and verse and be pedantic but use a draft
not the proper standard?

Don't ever go to court or they will throw you out with logic like that
 
K

Kelsey Bjarnason

[snips]

But availability of fixed with types isn't one of them

Oh? So I can use a uint32_t type where what I want is a uint32_t type,
and it will port to other C99 implementations?

No. It _may_ port to _some_ such implementations. It is even worse if I
use multiple such types.

My chess code prefers an 8-bit unsigned type for some things, a 16-bit
unsigned type for others and a 32-bit unsigned type for others. A 64-bit
unsigned type would be a boon as well.

Aha! uint8_t, uint16_t, uint32_t. Very good. Now, I'm guaranteed that
the relevant types will exist on any given implementation, right? No?
Ah. Maybe I can use, oh, uintleast8_t or whatever it is, so that even if
the type ends up being 32 bits, it is _at least_ the 8 I need? Hmm...
so's a char, and a short's at least 16 and a long's at least 32. So I'm
better off to just pretend these new int types don't exist at all, because
I simply *cannot* rely on them.
, it has always
been an issue. All C99 does is provide a standardised set of names.

If they're standardized, and we're not talking about a freestanding
implementation or some other oddball construct, then they exist, right?
Every conforming implementation will have them, right?

Nope. Not required. When "standard" ends up meaning "may or may not
exist, take a guess and pray" the term gets diluted somewhat.
If your code is processing a stream of say 16 bit data, you can either
assume the existence of a 16 (or 8) bit type

Like char and short? Oh, they're not required to be 8 and 16 bits, just
at least 8 and 16 bits. Meaning we've had perfectly good types for this
sort of thing since what, K&R?

The new int types were a potential boon, a way of saying "I don't care
what the machine supports natively, I want an 8 bit type even if the
little rotter needs to be emulated. I'll accept the speed overhead as
a tradeoff to the space overhead."

Instead it's a half-functioning accident which buys me absolutely nothing
of value, as far as I can see.
 
K

Kelsey Bjarnason

[snips]

In which case, the program you want can't be easily written for that
platform anyway.

True, but then I can code it once, using types which actually _do_ exist,
and have it run on all implementations.

Try that with the new int types. Oh, wait, you can't, because they're not
even required to exist.
 
K

Kelsey Bjarnason

[snips]

Yes. And _exactly_ n bits wide?

Nope. But we don't have that with the new int types, either, unless you
care to show where every implementation is _required_ to support, say,
uint8_t, uint16_t and uint32_t.

Ah, right. They're not. So this "exactly" nonsense is just that -
nonsense - as you can't expect it to work. At least the other way you
_do_ expect it to work.
void main() adds no functionality. Exact-width types do.

If void main adds no functionality, why's it so popular? As to the new
int types, explain what functionality they add when you can't even rely on
them existing. You *cannot* write code that uses them and expect it to
work on an arbitrary implementation, whereas you _can_ do this with
existing types.

Okay, in a strict sense they do add new functionality: they impose limits
on where code can be compiled, a feat which I don't think was ever managed
before by something as basic as an integer type.

Then again, I'm not really sure why one would think of this as a benefit.
 

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,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top