Why in stdint.h have both least and fast integer types?

G

GS

The stdint.h header definition mentions five integer categories,

1) exact width, eg., int32_t
2) at least as wide as, eg., int_least32_t
3) as fast as possible but at least as wide as, eg., int_fast32_t
4) integer capable of holding a pointer, intptr_t
5) widest integer in the implementation, intmax_t

Is there a valid motivation for having both int_least and int_fast?
 
C

Christian Bau

The stdint.h header definition mentions five integer categories,

1) exact width, eg., int32_t
2) at least as wide as, eg., int_least32_t
3) as fast as possible but at least as wide as, eg., int_fast32_t
4) integer capable of holding a pointer, intptr_t
5) widest integer in the implementation, intmax_t

Is there a valid motivation for having both int_least and int_fast?

Of course. If 16 bit integers are slow in your hardware, and 32 bit
integers are fast, then you would want int_least16_t to be 16 bit, and
int_fast16_t to be 32 bit. That covers about every computer that you can
buy in a shop.
 
J

James Harris

Christian Bau said:
Of course. If 16 bit integers are slow in your hardware, and 32 bit
integers are fast, then you would want int_least16_t to be 16 bit, and
int_fast16_t to be 32 bit. That covers about every computer that you can
buy in a shop.

Interesting example but what advantage does int_least16_t really give? If
we are talking about a few scalars wouldn't it be OK to let the compiler
represent them as int32s since they are faster? If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?
 
G

Gordon Burditt

The stdint.h header definition mentions five integer categories,
Interesting example but what advantage does int_least16_t really give? If

Space savings.
we are talking about a few scalars wouldn't it be OK to let the compiler
represent them as int32s since they are faster?

The programmer asked for memory savings over speed savings by
using int_least16_t over int_fast16_t. Speed doesn't do much good
if the program won't fit in (virtual) memory.

The few scalars might be deliberately made the same type as that
of a big array (or disk file) used in another compilation unit.
One example of this is storing data in dbm files using a third-party
library. When you retrieve data from dbm files, you get back a
pointer to the data, but it seems like it's usually pessimally
aligned, and in any case the dbm functions do not guarantee alignment,
so the way to use it is to memcpy() to a variable/structure of the
same type, and access it there. This fails if different compilations
have different sizes for int_least16_t.
If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

sizeof(int_least16_t) must be the same in all compilation units
that get linked together to make a program. (of course, array
subscripting, allocating a variable or array of int_least16_t, and
pointer incrementing all implicitly use that size) The optimizer
doesn't get much info on what size to make int_least16_t when the
only reference to it is:

void *vp;
size_t record_count;

qsort(vp, record_count, sizeof(int_least16_t), compar);

However, using that information, the compiler *MUST* choose now.
Perhaps before the part that actually allocates the array vp points
at is even written.

Gordon L. Burditt
 
C

Charlie Gordon

James Harris said:
Christian Bau said:
Of course. If 16 bit integers are slow in your hardware, and 32 bit
integers are fast, then you would want int_least16_t to be 16 bit, and
int_fast16_t to be 32 bit. That covers about every computer that you can
buy in a shop.

Interesting example but what advantage does int_least16_t really give? If
we are talking about a few scalars wouldn't it be OK to let the compiler
represent them as int32s since they are faster? If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

That would create incompatibilities between modules compiled with different
optimisation settings : a horrible side effect, that would cause unlimited
headaches !
My understanding is that int16_t must be exactly 16 bits.
int_least16_t should be the practical choice on machines where 16 bit ints have
to be emulated for instance, but otherwise would still be implemented as 16 bit
ints, whereas int_fast16_t would only be 16 bits if that's the fastest option.

There really is more than just the speed/size tradeoff: practical/precise is
another dimension to take into account.
 
K

Kevin Bracey

The stdint.h header definition mentions five integer categories,

1) exact width, eg., int32_t
2) at least as wide as, eg., int_least32_t
3) as fast as possible but at least as wide as, eg., int_fast32_t
4) integer capable of holding a pointer, intptr_t
5) widest integer in the implementation, intmax_t

Is there a valid motivation for having both int_least and int_fast?

The point you missed is that the _least types are supposed to be the
*smallest* types at least as wide, as opposed to the *fastest*, which are
designated by _fast.

A typical example might be the ARM, which (until ARMv4) had no 16-bit memory
access instructions, and still has only 32-bit registers and arithmetic
instructions. There int_least16_t would be 16-bit, but int_fast16_t might be
32-bit.

How you decide what's "fastest" is the tricky bit.

In a function, code like:

uint16_t a, b, c;

a = b + c;

would be slow on the ARM, because it would have to perform a 32-bit
addition, and then manually trim the excess high bits off. Using
uint_fast16_t would have avoided that. [*]

On the other hand, if you had an array of 2000 such 32-bit int_fast_16_ts you
were working on, having them as 16-bit might actually be faster because they
fit in the cache better, regardless of the extra core CPU cycles to
manipulate them.

That observation is likely to be true for pretty much any cached processor
where int_fast_XX != int_least_XX, so as a programmer it's probably going to
be a good idea to always use int_least_XX for arrays of any significant size.


[*] Footnote - some good ARM compilers have "significant bit tracking" that
can actually figure out when such narrowing is mathematically
unnecessary.
 
J

James Harris

Gordon Burditt said:
Space savings.

For scalars?
The programmer asked for memory savings over speed savings by
using int_least16_t over int_fast16_t. Speed doesn't do much good
if the program won't fit in (virtual) memory.

You expect to run out of memory? If that is really a problem why not use
int16_t?

More to the point, memory constraints are more likely to be a feature of
PICs or similar. In that case I would want to be able to tell the compiler
to fit the code in X words but to still optimize to be as fast as possible.
The few scalars might be deliberately made the same type as that
of a big array (or disk file) used in another compilation unit.
One example of this is storing data in dbm files using a third-party
library. When you retrieve data from dbm files, you get back a
pointer to the data, but it seems like it's usually pessimally
aligned, and in any case the dbm functions do not guarantee alignment,
so the way to use it is to memcpy() to a variable/structure of the
same type, and access it there. This fails if different compilations
have different sizes for int_least16_t.

Agreed but better, surely, to define the interface using int16_t. I expect
that int_least16_t would be different for different implementations, making
them incompatible with each other. This is an argument against the presence
of int_least16_t.
If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

sizeof(int_least16_t) must be the same in all compilation units
that get linked together to make a program. (of course, array
subscripting, allocating a variable or array of int_least16_t, and
pointer incrementing all implicitly use that size) The optimizer
doesn't get much info on what size to make int_least16_t when the
only reference to it is:

void *vp;
size_t record_count;

qsort(vp, record_count, sizeof(int_least16_t), compar);

However, using that information, the compiler *MUST* choose now.
Perhaps before the part that actually allocates the array vp points
at is even written.

Again, perhaps this is better written as int16_t, though I am beginning to
see there could be benefits to separating int_fast16_t.
 
J

James Harris

Charlie Gordon said:
James Harris said:
Christian Bau said:
Of course. If 16 bit integers are slow in your hardware, and 32 bit
integers are fast, then you would want int_least16_t to be 16 bit, and
int_fast16_t to be 32 bit. That covers about every computer that you
can
buy in a shop.

Interesting example but what advantage does int_least16_t really give?
If
we are talking about a few scalars wouldn't it be OK to let the compiler
represent them as int32s since they are faster? If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

That would create incompatibilities between modules compiled with
different
optimisation settings : a horrible side effect, that would cause
unlimited
headaches !
My understanding is that int16_t must be exactly 16 bits.
int_least16_t should be the practical choice on machines where 16 bit
ints have
to be emulated for instance, but otherwise would still be implemented as
16 bit
ints, whereas int_fast16_t would only be 16 bits if that's the fastest
option.

There really is more than just the speed/size tradeoff: practical/precise
is
another dimension to take into account.
 
J

James Harris

Interesting example but what advantage does int_least16_t really give?
If
we are talking about a few scalars wouldn't it be OK to let the compiler
represent them as int32s since they are faster? If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

That would create incompatibilities between modules compiled with
different
optimisation settings : a horrible side effect, that would cause
unlimited
headaches !

But isn't that exactly what int_least16_t does? It requires compilation
under the same rules for all modules which are to be linked together (and
that share data). Otherwise chaos will ensue. Given that the compilation
rules must match why have the three types of 16-bit integer? I can see the
need for two,

1) an integer that is at least N bits wide but upon which operations are as
fast as possible,
2) an integer than behaves as if it is exactly N bits wide - for shifts
etc.,

but I'm not sure about having a third option. This seems a bit baroque and
not in keeping with the lean nature that is the essence of C. It also seems
to me to confuse the performance vs. space issue with program logic. Is
this a set of data types designed by committee? I wonder what Ken Thompson
and Dennis Ritchie make of it.
My understanding is that int16_t must be exactly 16 bits.
int_least16_t should be the practical choice on machines where 16 bit
ints have
to be emulated for instance, but otherwise would still be implemented as
16 bit
ints, whereas int_fast16_t would only be 16 bits if that's the fastest
option.

There really is more than just the speed/size tradeoff: practical/precise
is
another dimension to take into account.

Agreed.
 
J

James Harris

Kevin Bracey said:
In message <[email protected]>


The point you missed is that the _least types are supposed to be the
*smallest* types at least as wide, as opposed to the *fastest*, which are
designated by _fast.

The *smallest* type as least as wide as 16 is of width 16, no? If it is
impossible to support an integer of width 16 (18-bit word, for instance)
how does the implementation deal with this standard's int16_t?
A typical example might be the ARM, which (until ARMv4) had no 16-bit
memory
access instructions, and still has only 32-bit registers and arithmetic
instructions. There int_least16_t would be 16-bit, but int_fast16_t might
be
32-bit.

How you decide what's "fastest" is the tricky bit.

Absolutely! There is no point making a data type "fast" if it is to be
repeatedly compared with values which are not the same width. Of course,
operations are fast or slow, not data values. Is the standard confusing two
orthogonal issues?
In a function, code like:

uint16_t a, b, c;

a = b + c;

would be slow on the ARM, because it would have to perform a 32-bit
addition, and then manually trim the excess high bits off. Using
uint_fast16_t would have avoided that. [*]

Yes, I think I'm coming round to having one that behaves as if it is
exactly 16 bits and another that behaves as if it has at least 16 bits.
On the other hand, if you had an array of 2000 such 32-bit int_fast_16_ts
you
were working on, having them as 16-bit might actually be faster because
they
fit in the cache better, regardless of the extra core CPU cycles to
manipulate them.

That observation is likely to be true for pretty much any cached
processor
where int_fast_XX != int_least_XX, so as a programmer it's probably going
to
be a good idea to always use int_least_XX for arrays of any significant
size.

I can see your point here. It's a subtlety. I still wonder, though, if I
wouldn't prefer to specify that array as int16_t. Specifying int_least16_t
is making me a hostage to the compiler. If I am taking in to account the
architecture of the underlying machine (in this case, primary cache size)
wouldn't I be better writing more precise requirements than int_leastX_t?
 
G

Gordon Burditt

The stdint.h header definition mentions five integer categories,
For scalars?

Yes. The compiler can't necessarily tell that there aren't malloc'd
arrays of these things also. Space savings might translate into
speed savings, too (since you seem to be stuck on fast == GOOD at
the expense of everything else) due to the operation of data caches.

Wouldn't it be OK to let the compiler represent int_fast16_t as
an int16_t on a machine which requires shift-and-mask operations to
BECAUSE IT TAKES LESS MEMORY? No, because int_fast16_t is supposed
to be fast. Likewise, int_least16_t is supposed to be small.
You expect to run out of memory? If that is really a problem why not use
int16_t?

int16_t is not guaranteed to exist at all, although it will
not be a problem on most current machines. Eventually it might
be an issue on machines where (char,short,int,long,long long) are
(32, 64, 128, 1024, and 8192) bits, respectively.
More to the point, memory constraints are more likely to be a feature of
PICs or similar. In that case I would want to be able to tell the compiler
to fit the code in X words but to still optimize to be as fast as possible.

int_least16_t is a way of telling the compiler to save memory.
If you want fast, use int_fast16_t.

It is quite possible for there to be a tight memory constraint on
some memory but not others in embedded devices, for example, limited
space for NONVOLATILE memory (represented, for example, as one
struct containing all the nonvolatile parameters) but more generous
memory for the program to run.
Agreed but better, surely, to define the interface using int16_t. I expect

int16_t need not exist.
that int_least16_t would be different for different implementations, making
them incompatible with each other. This is an argument against the presence
of int_least16_t.

If the data in question is not used outside the program (as would likely
be the case with arrays or with temporary disk files used only while
this program is running, portability of data between implementations
is not an issue.
If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

sizeof(int_least16_t) must be the same in all compilation units
that get linked together to make a program. (of course, array
subscripting, allocating a variable or array of int_least16_t, and
pointer incrementing all implicitly use that size) The optimizer
doesn't get much info on what size to make int_least16_t when the
only reference to it is:

void *vp;
size_t record_count;

qsort(vp, record_count, sizeof(int_least16_t), compar);

However, using that information, the compiler *MUST* choose now.
Perhaps before the part that actually allocates the array vp points
at is even written.

Again, perhaps this is better written as int16_t, though I am beginning to
see there could be benefits to separating int_fast16_t.

int16_t need not exist.

I was very disappointed in the standard for not requiring int_least11_t,
int_fast37_t, and, if it exists in the implementation, int53_t.
(or, in general, int_leastN_t, int_fastN_t, and if present, intN_t
for all prime values of N up to the maximum size available, and
preferably non-prime values as well). It would at least be clear
in arguments over int_fast37_t vs. int_least37_t that there is a
good chance that int37_t doesn't exist.

Gordon L. Burditt
 
C

Charlie Gordon

If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?
....
void *vp;
size_t record_count;

qsort(vp, record_count, sizeof(int_least16_t), compar);

Not a very safe way to call qsort().
I would recommend that vp be of the proper type and be used for the sizeof
operation :

int_least16_t fred[10000];
size_t record_count;
....
int_least16_t *vp = fred;

qsort(vp, record_count, sizeof(*vp), compar);

It is a pity our favorite language cannot manipulate types with more ease.
This would allow much safer definitions such as:

typedef void T; /* T can be any type */
void qsort(T *, size_t, size_t == sizeof(T), int (*comp)(const T *, const T *));
/* T can be any type, but parameter consistency can be enforced.

This kind of template would not require any run time support, and would generate
generic code, but allows to enforce type consistency, without opening C++
template Pandora's box.
 
F

Flash Gordon

The *smallest* type as least as wide as 16 is of width 16, no?

Only on implementations *having* a type that is exactly 16 bits wide.
If it
is impossible to support an integer of width 16 (18-bit word, for
instance) how does the implementation deal with this standard's
int16_t?

That's simple. It does not define int16_t
Absolutely! There is no point making a data type "fast" if it is to be
repeatedly compared with values which are not the same width. Of
course, operations are fast or slow, not data values. Is the standard
confusing two orthogonal issues?

There are generally speed issues which are related to size, such as a
system with a 32 bit address bus that can quickly access a 32 bit type
but has to either mask or shift the data to access a 16 bit value.

I can see your point here. It's a subtlety. I still wonder, though, if
I wouldn't prefer to specify that array as int16_t. Specifying
int_least16_t is making me a hostage to the compiler. If I am taking
in to account the architecture of the underlying machine (in this
case, primary cache size) wouldn't I be better writing more precise
requirements than int_leastX_t?

Well, when you port the SW to a 32 bit DSP processor that has absolutely
no support for 16 bit data and therefor does not provide int16_t? Such
an implementation can easily provide both int_least16_t and
int_fast16_t, anthough they would both be identical to int32_t
 
L

Lawrence Kirby

For scalars?

It probably makes sense to stick with fast variants for scalars. The
typical use for least variants would be in arrays and structures.
You expect to run out of memory? If that is really a problem why not use
int16_t?

Because it has no advantages over int_least16_t (except that it is shorter
to type, and maybe some minor modulo properties) and has a portability
disadvantage.
More to the point, memory constraints are more likely to be a feature of
PICs or similar. In that case I would want to be able to tell the compiler
to fit the code in X words but to still optimize to be as fast as possible.

Tht depends on whether the code or the data is subject to the memory
constraint (or some combination).
Agreed but better, surely, to define the interface using int16_t. I expect
that int_least16_t would be different for different implementations, making
them incompatible with each other. This is an argument against the presence
of int_least16_t.

Using int16_t doesn't fix the representation issues (byte order etc.). To
do this properly the external data format should be kept separate from the
representation of any internal datatype. You can do this just as well with
int_least16_t as int16_t.
If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

If the compiler has a 16 bit datatype available then this is what it
should use for int_least16_t. This means that int_least16_t is equivalent
to int16_t where there is a 16 bit type available, and int_least16_t
still works where there isn't. Indeed it is difficult to think of a
situation where using int16_t is a sensible idea.

Changing the model of object representation based on optimisation issues
seems a really bad idea even if it could be made to work. Keep it
simple - use the smallest available type. The programmer should be aware
that this saves data space, but not necessarily code space. He can then
make the appropriate judgements rather than having to 2nd guess the
compiler.
Again, perhaps this is better written as int16_t, though I am beginning to
see there could be benefits to separating int_fast16_t.

int16_t doesn't make much sense here, if you are worried about the space
used by the array use int_least16_t otherwise int_fast16_t. C programmers
have been doing that for years in a less formal way (the types are called
short and int). It is an approach that has proved to work very well.

Lawrence
 
J

James Harris

Tht depends on whether the code or the data is subject to the memory
constraint (or some combination).

You mean that (for a PIC) we might want to specify code constraints
separately from those for the data? Why would just asking the compiler to
try to fit the code+data image to X bytes not be sufficient?

Using int16_t doesn't fix the representation issues (byte order etc.). To
do this properly the external data format should be kept separate from
the
representation of any internal datatype. You can do this just as well
with
int_least16_t as int16_t.

Fully agree that anything represented externally to the module is part of
its interface and requires more precise specifications.
If, on the other hand,
these were stored in arrays
int_least16_t fred [10000];
why not let the compiler choose whether to store as int16 or int32,
depending on it's optimization constraints?

If the compiler has a 16 bit datatype available then this is what it
should use for int_least16_t. This means that int_least16_t is equivalent
to int16_t where there is a 16 bit type available, and int_least16_t
still works where there isn't. Indeed it is difficult to think of a
situation where using int16_t is a sensible idea.

This is helpful. I'm struggling to accepts these types. My feeling is that
as a programmer I want the following control,

1) The ability to define an integer, signed or unsigned, that will hold
values at least of a certain magnitude - almost but not quite the least_xx
types
2) The ability to hint to the compiler/linker that certain parts of the
code and/or certain data structures (referring to integers of type 1,
above) should be optimised for size. Otherwise all would be optimised for
speed. That way, the compiler can represent the data structures and produce
the code that best fits what is being asked taking in to account how the
data values are *used* in combination with each other throughout the
programe and taking in to account the target architecture.
3) Less often, the ability to define a binary 'integer' which will /behave/
as a bit string of a fixed length (incidentally, does this provide a
response to your comment: a situation where requiring an integer of fixed
size is a good idea - where it is primarily used to represent a binary
register or a set of flags rather than a number - and where one may want to
shift the value to the left, for example, and know that higher order bits
will be shifted out)

I'm not sure that the C types provide that control - or they provide the
control another way. They seem to approach the matter from a different
perspective, one that gives me some detailed control of the mechanism but
in an unnatural and cumbersome way. As an example, before deciding whether
a scalar should be least_xx or fast_xx I really need to check how it is
used and how it is combined /thoughout/ the code. If I want to change one
scalar type from least to fast or vice versa I need to check through the
code again to see how that will affect other operations. This is not in the
way my mind currently thinks. I'd rather the compiler did that for me and
leave me to express the code's *logic*. On the other hand having both types
does give me perhaps a greater degree of control. Frankly I'm not sure
which is best. I certainly don't want to have code with such as "#ifdef
int16_t" in it unless writing interface definitions - which as noted,
really require more precision than is provided by the optional types (bits,
endianness, ranges, representation of negative values).

Changing the model of object representation based on optimisation issues
seems a really bad idea even if it could be made to work. Keep it
simple - use the smallest available type. The programmer should be aware
that this saves data space, but not necessarily code space. He can then
make the appropriate judgements rather than having to 2nd guess the
compiler.

Noted. I'll have to consider this one. (Am not sure why it would be hard to
make work since we deal with ints etc all the time.)
 
G

Gordon Burditt

More to the point, memory constraints are more likely to be a feature of
You mean that (for a PIC) we might want to specify code constraints
separately from those for the data? Why would just asking the compiler to
try to fit the code+data image to X bytes not be sufficient?

Because ROM, RAM, and non-volatile RAM are generally sized separately
for an embedded device. They are not interchangable on the fly.
They are also not generally equivalent in cost.

Using int16_t is sensible where you really need an exactly-16-bits
representation and don't make the effort / don't want to pay the
performance penalty to make the code work when you've really got
more than 16 bits. (That is, put in a lot of "x &= 0xffff;"
statements to lop off any extra bits, deal with sign extension,
code shifts specially, etc.).

int16_t may also make sense for interfaces or external data (although
endianness is still an issue).
This is helpful. I'm struggling to accepts these types. My feeling is that
as a programmer I want the following control,

1) The ability to define an integer, signed or unsigned, that will hold
values at least of a certain magnitude - almost but not quite the least_xx
types

I'd like to see int_least17_t, int_least18_t, int_least19_t, etc.
especially for all the prime-valued N <= the maximum integer size.
Ok, this isn't quite like being able to declare
int[-4095 .. 4096] x;
OR int[7 .. 11] x;

In what way does int_leastN_t not satisfy your requirements, except
for being locked in to a small number of possible N values likely
to be available?
2) The ability to hint to the compiler/linker that certain parts of the
code and/or certain data structures (referring to integers of type 1,
above) should be optimised for size.

That's int_leastN_t.
Otherwise all would be optimised for
speed.

That's int_fastN_t.
That way, the compiler can represent the data structures and produce
the code that best fits what is being asked taking in to account how the
data values are *used* in combination with each other throughout the
programe and taking in to account the target architecture.

A compiler cannot change the size of types on the fly due to
optimization considerations when parts of the program are separately
compiled. All parts of the program that use the type must agree
on what size the type is. I suppose this is possible in a setup where
the "compiler" copies the source into an object file, and the "linker"
compiles the whole mess at once, but I don't know of any implementations
that do that.
3) Less often, the ability to define a binary 'integer' which will /behave/
as a bit string of a fixed length (incidentally, does this provide a
response to your comment: a situation where requiring an integer of fixed
size is a good idea - where it is primarily used to represent a binary
register or a set of flags rather than a number - and where one may want to
shift the value to the left, for example, and know that higher order bits
will be shifted out)

This is intN_t. I suppose it would be possible for a compiler to
implement int13_t using masking operations and treating shifts specially
to make it behave identically to a 13-bit int, while actually using
16 bits, assuming there is no 13-bit hardware support. It may also
be so slow as to not be worth ever using it.
I'm not sure that the C types provide that control - or they provide the
control another way.

They do provide the control, but perhaps not as fine-grained as to the
size of the type as some people would like.
They seem to approach the matter from a different
perspective, one that gives me some detailed control of the mechanism but
in an unnatural and cumbersome way. As an example, before deciding whether
a scalar should be least_xx or fast_xx I really need to check how it is
used and how it is combined /thoughout/ the code.

You pretty much ALWAYS need to consider how a type is used everywhere
if efficiency is a significant consideration. And remember, comparing
or assigning a int_fastN_t scalar to an element of an int_leastN_t
array is not necessarily faster than comparing a int_leastN_t to
an element of an int_leastN_t array, where these two are of different
size. The same applies to int vs. long or short vs. int.
If I want to change one
scalar type from least to fast or vice versa I need to check through the
code again to see how that will affect other operations. This is not in the
way my mind currently thinks. I'd rather the compiler did that for me and
leave me to express the code's *logic*.

If you are doing operations between an array of int_leastN_t and a scalar,
go with the logic of the code and use an int_leastN_t for the scalar.
The logic of the code doesn't include speed.
On the other hand having both types
does give me perhaps a greater degree of control. Frankly I'm not sure
which is best.

Nobody is really sure whether "register int" or "int" is better for
a scalar either.
I certainly don't want to have code with such as "#ifdef
int16_t" in it unless writing interface definitions - which as noted,
really require more precision than is provided by the optional types (bits,
endianness, ranges, representation of negative values).



Noted. I'll have to consider this one. (Am not sure why it would be hard to
make work since we deal with ints etc all the time.)

Gordon L. Burditt
 
F

Flash Gordon

You mean that (for a PIC) we might want to specify code constraints
separately from those for the data? Why would just asking the compiler
to try to fit the code+data image to X bytes not be sufficient?

<snip>

Please tell me how you will store
static int i;
in ROM whilst preserving the C semantics. Also tell me how you will
store code in RAM whilst the device is completely unpowered. Finaly,
explain how you will code with a Harvard Architecture device, such as
the TMS320C2x processors that I used to program in C where the data and
code are stored in completely seperate address spaces which are accessed
using completely different instructions.

I used to regularly work on systems where the were completely seperate
contraints on the code and data.
 
J

James Harris

Because ROM, RAM, and non-volatile RAM are generally sized separately
for an embedded device. They are not interchangable on the fly.
They are also not generally equivalent in cost.

Agreed. I was thinking of a burned image rather than updateable space.


My feeling is that
as a programmer I want the following control,

1) The ability to define an integer, signed or unsigned, that will hold
values at least of a certain magnitude - almost but not quite the
least_xx
types

I'd like to see int_least17_t, int_least18_t, int_least19_t, etc.
especially for all the prime-valued N <= the maximum integer size.
Ok, this isn't quite like being able to declare
int[-4095 .. 4096] x;
OR int[7 .. 11] x;

In what way does int_leastN_t not satisfy your requirements, except
for being locked in to a small number of possible N values likely
to be available?


It seems to me to approach this from a subtly different angle. Correct me
if I am wrong but this seems to be saying not just, "at least of a certain
magnitude," (as I was wanting) but also, "as small as possible and
convenient on the architecture, but not necessarily exact." This is more
than a hint to the compiler. It is a demand (if I understand correctly).
This integer will _not_ be bigger than the predefined at-least-as-big-as-N
under any circumstances. As such it may inhibit code optimisation rather
than enhance it unless the programmer is careful to consider how that
variable or array so declared is used in the code.

For example, I know that nearly all of my code needs numeric quantities
that are at least 16-bits so I declare a bunch of integers at least as big
as 16-bit. That's it. In simple terms, if I am compiling for small size I
want it to use the smallest integers it can in arrays. If I am compiling
for speed I want it to use the fastest operations it can. (In reality I
think the compiliation for /smallest/ size is anachronistic. If I want
small I normally want to try to fit to a certain size but still want as
fast as possible.)

It seems that int_least takes that choice away from the compilation step
and embeds it, possibly in conflicting ways, in the code. I guess I'm
suggesting int_least and int_fast should be one and the same. Neither is
int_exact which is, in fact, useful!

That's int_leastN_t.


That's int_fastN_t.

I don't think so. It is a hack. It is possibly included to satisfy the
16-bit quantities, faster 32-bit operations model. int_fastN_t is a
nonsense. It is not faster. It is saying to choose a wider integer for this
variable or elements of this array if, on this architecture, operations on
this size of integer are normally faster. It takes no consideration
whatsoever as to what operations are performed on those integers in the
code.

Say the world is not the rosy, modern, mainstream, familiar, Intel-ish
16/32-bit paradigm and we have a machine which performs addition and
subtraction faster on 32-bit integers and performs multiplication and
division faster on 16-bit rather than 32-bit values. ie. it has a 32-bit
adder but only a 16-bit multiplier (to give a 32-bit result). What, then,
is int_fast16_t? There is no such thing. The fastest operations depend on
how the values are to be used in the code, particularly in the innermost
loops.

A compiler cannot change the size of types on the fly due to
optimization considerations when parts of the program are separately
compiled. All parts of the program that use the type must agree
on what size the type is. I suppose this is possible in a setup where
the "compiler" copies the source into an object file, and the "linker"
compiles the whole mess at once, but I don't know of any implementations
that do that.

Agreed that the compile/link step needs to be unified to handle this.

This is intN_t. I suppose it would be possible for a compiler to
implement int13_t using masking operations and treating shifts specially
to make it behave identically to a 13-bit int, while actually using
16 bits, assuming there is no 13-bit hardware support. It may also
be so slow as to not be worth ever using it.

It is intN_t but, sadly, intN_t is optional. If the code is to be portable
I have to fiddle about with the declaraions or, more likely, use
int_leastN_t and bitmasks. Again this is nonsense. If I have to use
bitmasks I may be better going for int_fastN_t and masking those. On the
other hand, if I use the "faster" integers and bitmask them, while I will
get faster code on the right hardware I've maybe made a rod for the back of
true right-sized-word hardware. Maybe a clever compiler could get me out of
this trap but I'd rather not have been put in it in the first place. And
then there are all those masks littering the code.


Nobody is really sure whether "register int" or "int" is better for
a scalar either.

Valid point. Having said that I think there is a difference here. AFAIK
'register' is a hint or suggestion and need not be followed. I assume the
least and fast types are directives.

I fully agree with the point you mentioned above - ints of sizes other than
the well known ones. I don't know if they would be used much but they would
have their place and allow a fine degree of control for someone carefully
writing transportable code.
 
J

James Harris

<snip>

Please tell me how you will store
static int i;
in ROM whilst preserving the C semantics. Also tell me how you will
store code in RAM whilst the device is completely unpowered. Finaly,
explain how you will code with a Harvard Architecture device, such as
the TMS320C2x processors that I used to program in C where the data and
code are stored in completely seperate address spaces which are accessed
using completely different instructions.

I was thinking about a code image (including read-only data). Thanks for
pointing out the separation of address spaces even for that.
 
G

Gordon Burditt

It seems to me to approach this from a subtly different angle. Correct me
if I am wrong but this seems to be saying not just, "at least of a certain
magnitude," (as I was wanting) but also, "as small as possible and
convenient on the architecture, but not necessarily exact." This is more
than a hint to the compiler. It is a demand (if I understand correctly).
This integer will _not_ be bigger than the predefined at-least-as-big-as-N
under any circumstances. As such it may inhibit code optimisation rather
than enhance it unless the programmer is careful to consider how that
variable or array so declared is used in the code.

Having the code optimizer determine the size of a type based on
looking at the code is darn near impossible and I don't know of any
compiler that can do it. A nearly impossible to bypass hurdle is
that all parts of separate compilations have to agree on the size
of a type, so any attempt would pretty much have to defer all code
generation to what's commonly called the "linking" step. "Object
code" becomes lightly preprocessed source code. Even with that is
the hurdle that all programs that use files with these types in
them (running on the same machine) need to use the same size for
each type. It's just too much trouble for too little benefit.

You can have a compiler that lets you determine the size of a type
based on compiler flags (which amounts to a different implementation).
There is nothing preventing an implementor (or in an implementation
with text include files, possibly a user of the compiler) from
hacking up <inttypes.h> with #ifdefs on COMPILE_FOR_SPEED to change
what is used for int_leastN_t, and using -DCOMPILE_FOR_SPEED to
select the implementation. However, you'd better use the same
option on all parts of the same program. That may mean SPEED vs.
SPACE libraries, which you may not have source code for.

For example, I know that nearly all of my code needs numeric quantities
that are at least 16-bits so I declare a bunch of integers at least as big
as 16-bit. That's it. In simple terms, if I am compiling for small size I
want it to use the smallest integers it can in arrays. If I am compiling
for speed I want it to use the fastest operations it can. (In reality I

What do you mean by "compile for small size" or "compile for speed"?
Is this controlled by flags passed to the compiler? ANSI C specifies
no such choice. It doesn't rule it out, either, and I believe there
are compilers that let you select sizeof(int) from two choices with
flags. I would certainly want the type sizes controlled independently
from other optimizations. Type sizes must match across all parts
of a program. Code optimization need not.

(There is, for example, one file in the code of a well-known database
program which is often compiled without optimization because compiling
with optimization tends to run the compilation step out of swap
space on typical compilations, and the parser tables generated can't
really be optimized much anyway. Also, turning off code optimization
is sometimes necessary because the generated code is broken).

Forget about the optimization step determining the size of a type.
It won't happen.
think the compiliation for /smallest/ size is anachronistic. If I want

No, it isn't. And compiling for smallest size data may BE the fastest.
Consider how processor cache operates. Consider how "swapping" and
"paging" work.
small I normally want to try to fit to a certain size but still want as
fast as possible.)

Not everyone is a speed freak. And sometimes the programmer knows
that smaller is faster, especially if it's smaller in memory vs.
disk file.
It seems that int_least takes that choice away from the compilation step
and embeds it, possibly in conflicting ways, in the code.

WHAT choices at the compilation step? Forget about the optmization step
changing the size of a type. It won't happen.
I guess I'm
suggesting int_least and int_fast should be one and the same. Neither is
int_exact which is, in fact, useful!

It doesn't matter how darn fast something is if it won't fit in
available memory!

int_exact may be useful but it has the potential for being darn
slow, too, especially if the implementation decided to synthesize
all of them not supported directly by hardware: e.g. int17_t done
with masks.
I don't think so. It is a hack. It is possibly included to satisfy the
16-bit quantities, faster 32-bit operations model.

The bigger the native int gets, the more likely it is that accessing
smaller chunks of memory will require inefficient methods to access
small pieces. I wouldn't be too surprised to see 16-bit-addressable
machines (with a 64-bit or 128-bit int) using a Unicode character
set in the future, where accessing 8-bit (legacy ASCII) quantities
requires a shift-and-mask operation, and accessing a 32-bit quantity
is no faster than accessing a 64-bit quantity.
int_fastN_t is a
nonsense. It is not faster.

If it avoids shift-and-mask, it's probably faster.
It is saying to choose a wider integer for this
variable or elements of this array if, on this architecture, operations on
this size of integer are normally faster. It takes no consideration
whatsoever as to what operations are performed on those integers in the
code.

Forget about the optimizer choosing the size of a type. It's not
going to happen.

Most of the operations performed on an N-bit type are moving them
around, or are of equivalent speed.
Say the world is not the rosy, modern, mainstream, familiar, Intel-ish
16/32-bit paradigm and we have a machine which performs addition and
subtraction faster on 32-bit integers and performs multiplication and
division faster on 16-bit rather than 32-bit values. ie. it has a 32-bit
adder but only a 16-bit multiplier (to give a 32-bit result). What, then,
is int_fast16_t? There is no such thing. The fastest operations depend on
how the values are to be used in the code, particularly in the innermost
loops.

The speed metric I'd probably use for deciding what to make
int_leastN_t is how fast you can load, store, or assign a quantity
of the given size. There are a number of operations that are
generally performed as fast as a load or a store for a given size
integer quantity. Addition, subtraction, bitwise operations,
compare, etc. generally qualify, so if you can move that size around
quickly, you can also do simple operations on it at no extra cost.
Multiplication and division generally do not fall into this class.

Forget about the optimizer choosing the size of a type. It's not
going to happen.
Agreed that the compile/link step needs to be unified to handle this.

So as a practical matter, it's not going to happen. Among other
problems, all the people who distribute proprietary code libraries
are going to object that "object code" is now too close to source
code and it makes everything involuntary open-source. Plus, it
explodes the combinations of code libraries needed: you've got 3
choices for int_least16_t, and 2 choices for int_least32_t, making
6 copies of every library.

And even putting everything in the link step doesn't solve the
problem: sometimes you need several programs to all agree on the
type sizes to access data they pass between themselves.
It is intN_t but, sadly, intN_t is optional. If the code is to be portable
I have to fiddle about with the declaraions or, more likely, use
int_leastN_t and bitmasks. Again this is nonsense. If I have to use

Well, is it really any better than making the compiler use the type
of int_leastN_t and bitmasks and shifts? Very few platforms will
support int17_t natively. Of course, there's not a lot of demand
for that size, either. I can see reasonable arguments for int48_t,
though, where 32 bits won't do but 64 bits is overkill. (It may
be a few years before we hit the 280-terabyte hard disk size barrier).
bitmasks I may be better going for int_fastN_t and masking those. On the
other hand, if I use the "faster" integers and bitmask them, while I will
get faster code on the right hardware I've maybe made a rod for the back of
true right-sized-word hardware. Maybe a clever compiler could get me out of
this trap but I'd rather not have been put in it in the first place. And
then there are all those masks littering the code.




Valid point. Having said that I think there is a difference here. AFAIK
'register' is a hint or suggestion and need not be followed. I assume the
least and fast types are directives.

A register directive should be followed to the extent that taking
its address must be diagnosed as an error. This is not something
that can be left to the optimization stage. Otherwise, the code
can't tell whether it was followed or not.

On the other hand, the code CAN tell the difference between
int_leastN_t and int_fastN_t if they are different sizes: sizeof.

Incidentally, if you really want to try out different cases, there's
nothing prohibiting you from using your own typedefs which you can
conditional as needed. For example, rid_type might be the typedef
for a record ID in a database, and it can be int_least16_t,
int_least32_t, or int_least64_t depending on target platform,
licensing (e.g. the demo version only does 65535 records), and
application. This also would let you make separate decisions
for instances of different types, where you know more about how
the types will be used than the compiler.

I fully agree with the point you mentioned above - ints of sizes other than
the well known ones. I don't know if they would be used much but they would
have their place and allow a fine degree of control for someone carefully
writing transportable code.

Gordon L. Burditt
 

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

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top