Discussion:
Avoid 'int' and associates.
(too old to reply)
Mr Flibble
2015-06-14 12:36:18 UTC
Permalink
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next); instead
one should use the typedefs from <cstdint> instead.

A consequence of this rule is that we must never use 'auto' with integer
literals such as:

auto i = 42;

or

auto i = 42u;

instead we write:

int32_t i = 42;

or

uint32_t i = 42u;

The fact we have to do this is due to shortcoming of the current C++
Standard; what we need is something like:

auto i = 42s32; // signed, 32-bits

or

auto i = 42u32; // unsigned, 32-bits

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Melzzzzz
2015-06-15 00:00:22 UTC
Permalink
On Sun, 14 Jun 2015 06:36:18 CST
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their
size and value range can differ from one implementation to the next);
instead one should use the typedefs from <cstdint> instead.
A consequence of this rule is that we must never use 'auto' with
auto i = 42;
or
auto i = 42u;
int32_t i = 42;
or
uint32_t i = 42u;
I would never use auto for simple initialization and when types are
obvious (like int), rather I would use auto to avoid long templates.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Francis Glassborow
2015-06-15 00:07:45 UTC
Permalink
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next); instead
one should use the typedefs from <cstdint> instead.
If it matters then your program is already dangerous and relying on
undefined behaviour. Note that unless your program results in
overflow/underflow there is no problem with signed types.

If your program is using unsigned types and is relying on the defined
behaviour for over/underflow then you already have an essentially
non-portable program because there is no requirement for exact sizes to
exist. It is perfectly OK for all unsigned int types to be 64-bit. I do
not know any system where this is the case but there are certainly
systems where unsigned char, unsigned short, unsigned int and unsigned
long are all 32-bit.

In almost all cases you should simply use the standard type that
guarantees sufficient range for your needs.

Finally, you can simply use long long and unsigned long long everywhere
and mark all literals as either LL or ULL.

I think the added complexity of using the <cstdint> typedefs routinely
whether needed or not is a recipe for error.

Francis
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James K. Lowden
2015-06-15 00:11:00 UTC
Permalink
On Sun, 14 Jun 2015 06:36:18 CST
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their
size and value range can differ from one implementation to the next);
instead one should use the typedefs from <cstdint> instead.
I disagree with this assertion. Hardware evolves, and nonspecialized
variables evolve along with it.

It's not strictly correct that "int" and "long" are nonportable. It's
more correct to say their size is adapted by the compiler to the
machine. Except in the case of I/O, ISTM that's an advantage.

We have working code today written in the era of 16-bit machines, when
32-bit accesses required two memory reads and extra CPU cycles to
compute. We have even more code dating from the VAX era, including
every operating system in common use. The transition to 64-bit
hardware was made easier, I would argue, by *not* specifying variable
sizes in terms of bits. Indeed, the biggest change has been away from
bare "int" to semantic, opaque types like size_t and off_t.

I'm very glad we have <cstdint>. It makes simple something that used
to ugly and arcane, and it a pleasure to use for e.g. network
programming. It's a mistake to think it makes ordinary variables
obsolete. Size usually doesn't matter very much, and is relative, and
changes over time.

--jkl
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper
2015-06-15 00:11:15 UTC
Permalink
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next); instead
one should use the typedefs from <cstdint> instead.
A consequence of this rule is that we must never use 'auto' with integer
auto i = 42;
or
auto i = 42u;
int32_t i = 42;
or
uint32_t i = 42u;
The fact we have to do this is due to shortcoming of the current C++
auto i = 42s32; // signed, 32-bits
or
auto i = 42u32; // unsigned, 32-bits
That's going a bit too far, in my opinion. First of all, whenever using
an interface, it's generally best to use the types specified for that
interface, even if they include 'int', 'short', or 'long'.

Secondly, if there's a traditional type name that's essentially
equivalent to one of the size-named types, I'll normally use the
traditional name instead, simply to save on my typing (though the
savings are bigger for the signed types). Types I consider essentially
equivalent are:

[u]int_least8_t [un]signed char
[u]int_least16_t [unsigned] short
[u]int_fast16_t [unsigned] int
[u]int_fast32_t [unsigned] long

Much of my code is targeted specifically at POSIX, which guarantees that
CHAR_BIT == 8, in which case I'm also willing to treat [un]signed char
as equivalent to [u]int8_t, but only if I've inserted the following
protection in the same translation unit:

#include <limits.h>
#if CHAR_BIT != 8
#error CHAR_BIT != 8
#endif
--
James Kuyper


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Maciej Sobczak
2015-06-15 00:11:33 UTC
Permalink
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable
Nonsense. They are very portable - the standard carefully specifies the minimum ranges that the implementation has to cover with
these types, so it is possible to write a portable program with them.

It is not these types which are a problem - the problem is with people who try to rely on the representation of these types to do
things that are very likely undefined anyway (like direct I/O, object overlays, etc.). This is why the coding standards that are
mostly obsessed with replacing these types with their "sized" alternatives (like int32_t) are those that usually target embedded
systems, where such practices are common. But it has nothing to do with being "modern".
Post by Mr Flibble
and unsafe
There is nothing inherently unsafe (except perhaps from overflows, but this exists also with sized types) in these types. Again, the
problem is with people who use them for things that are very likely undefined anyway.
Post by Mr Flibble
auto i = 42s32; // signed, 32-bits
Nonsense. There is absolutely no added value in specifying the exact type on the right side and pretend that the left side is
"automatically" inferred. You might as well write this:

int32_t i = 42;

without introducing any new crap to the language.

Side note: check how Ada solved all of these problems, it gives some refreshing perspective.

--
Maciej Sobczak * http://www.inspirel.com
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Paavo Helde
2015-06-15 02:24:54 UTC
Permalink
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next); instead
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).

Note that the actually needed range often depends on the application
domain requirements and the hardware capabilities, both of which are out
of the control of the programmer and can change in time. So, at the time
of writing the programmer often does not have sufficient knowledge to
select the "correct" fixed-size type. The only exception is when it is
known that the numbers are relatively small and the limits do not matter,
and this is exactly what the generic int type is meant for.

For example, it used to be that the number of pixels in a single medical
image (2D or 3D) fits in 32 bits, but this assumption is slowly starting
to break. So all those apps who have used e.g. std::uint32_t for the
pixel index type will probably need a potentially painful upgrade cycle
in the future.

Instead of relying on a fixed type, the program should define a typedef
for each different usage case of int, which can be upgraded more cleanly
and easily when the need arises. The typedef itself can be based on a
fixed-size type or then not, this is not so crucial any more.

This is not something new, there is a reason why STL contains several
such typedefs as e.g. std::string::size_type. Using fixed-size types
would not be possible here. Fixed-size types should be directly used only
in places where the type sizes are indeed fixed, e.g. when composing a
TIFF file IFD in memory or something like that.

Cheers
Paavo
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Brown
2015-06-15 13:13:45 UTC
Permalink
Post by Mr Flibble
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next);
instead
Post by Mr Flibble
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".

If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.


We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".

Personally, I have very little use of "short" or "long", however. Bar
consistency with existing code, I can't see any use of "(unsigned)
short" that would not be better suited with "(u)int16_t", nor any use of
"long" that would not be better with "int32_t" or "int64_t", according
to what you actually /need/. And I think "unsigned char" and "signed
char" are meaningless monstrosities - plain "char" is good for character
data, while "uint8_t" and "int8_t" are appropriate for data bytes and
small unsigned or signed numbers. (On platforms without 8-bit chars,
(u)int_least8_t is better than (un)signed char.)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Francis Glassborow
2015-06-15 17:22:56 UTC
Permalink
Post by David Brown
Post by Mr Flibble
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next);
instead
Post by Mr Flibble
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".
If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.
We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
Personally, I have very little use of "short" or "long", however.
So both C and C++ provide an integer type that is guaranteed to be at
least 32-bits, so why would I not use that when I need a 32-bit integer?
That is why int32_t better? Note that on systems with 32-bit int, long
int is usually also 32 bits.

And where I need 64 bits the (ugly) long long int meets my need.

If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)


I agree that short is pretty useless these days. It would have made more
sense if it had been an exact 16-bit integer type.

Francis
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble
2015-06-15 19:02:57 UTC
Permalink
Post by Francis Glassborow
Post by David Brown
Post by Mr Flibble
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next);
instead
Post by Mr Flibble
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".
If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.
We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
Personally, I have very little use of "short" or "long", however.
So both C and C++ provide an integer type that is guaranteed to be at
least 32-bits, so why would I not use that when I need a 32-bit integer?
That is why int32_t better? Note that on systems with 32-bit int, long
int is usually also 32 bits.
'int' is only guaranteed to be at least 16 bits but the actual problem
is the *at least* part: it can mean *different* sizes and value ranges
on *different* implementations resulting in *different* or even
*dangerous behaviour*. If you want a type that behaves like 'int' then
you should be explicit about it in your code by using 'int_fast16_t' but
absolute care must be taken when using such variable types.
Post by Francis Glassborow
And where I need 64 bits the (ugly) long long int meets my need.
If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)
You should be writing code such that the underlying type doesn't
actually matter; that is part of the rationale for <cstdint> in the
first place.

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Francis Glassborow
2015-06-15 20:54:33 UTC
Permalink
Post by Mr Flibble
Post by Francis Glassborow
Post by David Brown
Post by Mr Flibble
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next);
instead
Post by Mr Flibble
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".
If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.
We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
Personally, I have very little use of "short" or "long", however.
So both C and C++ provide an integer type that is guaranteed to be at
least 32-bits, so why would I not use that when I need a 32-bit integer?
That is why int32_t better? Note that on systems with 32-bit int, long
int is usually also 32 bits.
'int' is only guaranteed to be at least 16 bits but the actual problem
is the *at least* part: it can mean *different* sizes and value ranges
on *different* implementations resulting in *different* or even
*dangerous behaviour*. If you want a type that behaves like 'int' then
you should be explicit about it in your code by using 'int_fast16_t' but
absolute care must be taken when using such variable types.
If my code becomes dangerous I am already in undefined behaviour land
and that effectively means that I am relying on some behaviour that
breaks if int has more than 16-bits. Please give an example of code
which works for a 16-bit int but is broken for an int with more bits.
Post by Mr Flibble
Post by Francis Glassborow
And where I need 64 bits the (ugly) long long int meets my need.
If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)
You should be writing code such that the underlying type doesn't
actually matter; that is part of the rationale for <cstdint> in the
first place.
Not really, the idea was to allow systems that had more types available
over and above those required by the standard to allow programmers to
express their needs. And the rationale was a purely C one and I doubt
that it would be in C++ other than for compatibility reasons.

For example it is possible that on a particular platform a 32-bit
integer type performs faster than a 16-bit one. However that has a smell
of premature optimisation.

In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)

Anyway you are free to use anything you want even if most of us would
not do so and would often ask for change in a code review. Typedefs are
a potential source of problems, particularly in C++ where overloading
can be changed by a change in an underlying type.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble
2015-06-15 21:54:45 UTC
Permalink
Post by Francis Glassborow
Post by Mr Flibble
Post by Francis Glassborow
Post by David Brown
Post by Mr Flibble
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next);
instead
Post by Mr Flibble
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".
If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.
We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
Personally, I have very little use of "short" or "long", however.
So both C and C++ provide an integer type that is guaranteed to be at
least 32-bits, so why would I not use that when I need a 32-bit integer?
That is why int32_t better? Note that on systems with 32-bit int, long
int is usually also 32 bits.
'int' is only guaranteed to be at least 16 bits but the actual problem
is the *at least* part: it can mean *different* sizes and value ranges
on *different* implementations resulting in *different* or even
*dangerous behaviour*. If you want a type that behaves like 'int' then
you should be explicit about it in your code by using 'int_fast16_t' but
absolute care must be taken when using such variable types.
If my code becomes dangerous I am already in undefined behaviour land
and that effectively means that I am relying on some behaviour that
breaks if int has more than 16-bits. Please give an example of code
which works for a 16-bit int but is broken for an int with more bits.
Post by Mr Flibble
Post by Francis Glassborow
And where I need 64 bits the (ugly) long long int meets my need.
If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)
You should be writing code such that the underlying type doesn't
actually matter; that is part of the rationale for <cstdint> in the
first place.
Not really, the idea was to allow systems that had more types available
over and above those required by the standard to allow programmers to
express their needs. And the rationale was a purely C one and I doubt
that it would be in C++ other than for compatibility reasons.
For example it is possible that on a particular platform a 32-bit
integer type performs faster than a 16-bit one. However that has a smell
of premature optimisation.
In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)
Can you back that assertion up with any facts at all?
Post by Francis Glassborow
Anyway you are free to use anything you want even if most of us would
not do so and would often ask for change in a code review. Typedefs are
a potential source of problems, particularly in C++ where overloading
can be changed by a change in an underlying type.
You are speaking for a lot of people there. As far as code reviews are
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).

You should be coding to an interface; if the interface is legacy and
takes an 'int' then you should of course perform a safe type conversion
to an 'int' however any new interfaces that are within your remit to
define should be using the typedefs from <cstdint> to ensure
cross-platform portability and correct program operation.

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper
2015-06-16 03:04:20 UTC
Permalink
...
Post by Mr Flibble
Post by Francis Glassborow
In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)
Can you back that assertion up with any facts at all?
Which assertion are you referring to? Normally, "that" refers to the
most recently mentioned thing that it could refer to, but his very last
assertion is easy to back up: 7.20.1.1, describing the Exact-width
Types, says in paragraph 3: "These types are optional". His earlier
assertions are much more questionable, but if you meant to refer to one
of them, you should have used some phrase other than "that assertion".

...
Post by Mr Flibble
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
I'm not impressed by MISRA's guidelines in general, and this one fits
into that pattern. I've only heard of them second-hand; a copy of those
guidelines is too expensive to justify buying one if you don't have an
obligation to follow those guidelines. However, what I've heard from
other people about those guidelines has not impressed me (and most of
those people were MISRA supporters).
--
James Kuyper


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Brown
2015-06-16 13:05:12 UTC
Permalink
Post by James Kuyper
...
Post by Mr Flibble
Post by Francis Glassborow
In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)
Can you back that assertion up with any facts at all?
Which assertion are you referring to? Normally, "that" refers to the
most recently mentioned thing that it could refer to, but his very last
assertion is easy to back up: 7.20.1.1, describing the Exact-width
Types, says in paragraph 3: "These types are optional". His earlier
assertions are much more questionable, but if you meant to refer to one
of them, you should have used some phrase other than "that assertion".
...
Post by Mr Flibble
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
I'm not impressed by MISRA's guidelines in general, and this one fits
into that pattern. I've only heard of them second-hand; a copy of those
guidelines is too expensive to justify buying one if you don't have an
obligation to follow those guidelines. However, what I've heard from
other people about those guidelines has not impressed me (and most of
those people were MISRA supporters).
MISRA standards are only £10 or £15 for the pdfs - it's not /that/
expensive! (But of course any cost makes the whole process a lot more
inconvenient, especially if you just want a quick look for curiosity.)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper
2015-06-16 20:59:05 UTC
Permalink
On 06/16/2015 09:05 AM, David Brown wrote:
...
Post by David Brown
Post by James Kuyper
I'm not impressed by MISRA's guidelines in general, and this one fits
into that pattern. I've only heard of them second-hand; a copy of those
guidelines is too expensive to justify buying one if you don't have an
obligation to follow those guidelines. However, what I've heard from
other people about those guidelines has not impressed me (and most of
those people were MISRA supporters).
MISRA standards are only £10 or £15 for the pdfs - it's not /that/
expensive! (But of course any cost makes the whole process a lot more
inconvenient, especially if you just want a quick look for curiosity.)
IIRC, the last time I looked it was several hundred US$. A year ago, I
would have thought that £10 it would be almost worth paying for, just
out of curiosity. However, since the twins arrived I'm paying closer
attention to my money.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Brown
2015-06-16 22:47:07 UTC
Permalink
Post by James Kuyper
...
Post by David Brown
Post by James Kuyper
I'm not impressed by MISRA's guidelines in general, and this one fits
into that pattern. I've only heard of them second-hand; a copy of those
guidelines is too expensive to justify buying one if you don't have an
obligation to follow those guidelines. However, what I've heard from
other people about those guidelines has not impressed me (and most of
those people were MISRA supporters).
MISRA standards are only £10 or £15 for the pdfs - it's not /that/
expensive! (But of course any cost makes the whole process a lot more
inconvenient, especially if you just want a quick look for curiosity.)
IIRC, the last time I looked it was several hundred US$. A year ago, I
would have thought that £10 it would be almost worth paying for, just
out of curiosity. However, since the twins arrived I'm paying closer
attention to my money.
That must have been a /long/ time ago - or perhaps you are mixing it
with some other standards (such as the current C++ standard, which is an
absurd $265).

If you have anything specific you want to ask about MISRA, let me know
and I can look it up - I can't send you a copy (since it would be
copyright infringement, and the pdf is watermarked with my name).
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Scott Lurndal
2015-06-16 15:54:43 UTC
Permalink
Post by Mr Flibble
Post by Francis Glassborow
For example it is possible that on a particular platform a 32-bit
integer type performs faster than a 16-bit one. However that has a smell
of premature optimisation.
In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)
Can you back that assertion up with any facts at all?
Probably not. Most of the C++ code that I've worked on over the
last 20+ years uses these types (before they were standardized,
and with names like u32, uint32, uint32_t etc).

Granted most of that code ran sans OS (it was the OS), and required
fixed types to map to various hardware registers.

However, absent API requirements for other types, I would prefer
using types for which I understand the characteristics in all
conditions, thus I prefer the explicitly sized types. Having
run into many issues in the past porting software from 16-bit
ints to 32-bit ints (and from 32-bit longs to 64-bit longs),
I would never advocating using 'int' for anything.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
legalize+ (Richard)
2015-06-16 20:59:16 UTC
Permalink
[Please do not mail me a copy of your followup]
Post by Scott Lurndal
Granted most of that code ran sans OS (it was the OS), and required
fixed types to map to various hardware registers.
This is the situation where I think the size of the data really *does*
matter and it's important to use sized types and not the implicit size
of int, long, etc. Things like structures representing byte streams
passed across the network (and you might do network-to-host byte
reordering in place on that structure), raw byte streams read from or
written to files, raw bytes transmitted between processes through
shared memory segments and so-on.

I've got some code im my open source project that doesn't use
specifically sized types for some binary file I/O and it's a mess right
because they used generic types. So I am certainly sympathetic to
cases where it matters.

My assertion is that it simply doesn't matter in *every* case.
Post by Scott Lurndal
However, absent API requirements for other types, I would prefer
using types for which I understand the characteristics in all
conditions, thus I prefer the explicitly sized types. Having
run into many issues in the past porting software from 16-bit
ints to 32-bit ints (and from 32-bit longs to 64-bit longs),
I would never advocating using 'int' for anything.
Here, I disagree. The size of every int in a program isn't a
portability concern. What's important is deciding which variables need
specific sizes and which don't.[*]

I've seen code where the compiler's default size of an int was 16-bits
and everywhere they wanted to iterate over containers or whatnot it was
int16_t all over the place. Then you move to a compiler where the
defaault size of an int is 32-bits. The fact that all those ints were
marked as 16-bits is now erroneous and simply a distraction. How do
you know which ones really needed to be 16-bits and which were 16-bits
simply because that was the default size of an int? Forcing them all
into a 16-bit straight jacket impedes portability instead of enhancing
it.

In other words, like most things in programming, it's a matter of good
judgment. Simplistically applying a rule like "never use int" is
opening up your skull and dumping your brains in the garbage. There is
a time when specifically sized types are important.

For most of the C++ I have worked on in the past 25 years, it was
important in only a very few cases. Working on code where the team
insisted on sizing every single named quantity in the application was
tedious and yielded little to no value. I have done very little
programming in embedded environments with strict resource limits and I
can see how someone who spent 25 years in that environment would
consider it indispensible that everything be specifically sized. So it
varies with experience and problem domain.

But this is just another reason to advocate for proper application of
good judgment for your problem domain instead of adopting a simplistic
rule. Even within a problem domain, things can change over time.
Embedded processors today have access to many more resources than they
did in the 80s when 64 users time shared out of 128KB of main memory
and an embedded CPU was lucky to have 128 bytes of RAM and 16K of ROM.

[*] Aside: if sizing is all that important, does that mean you encode
the byte size of a struct into its name? I mean, if it's really that
important for int to be declared to be a specific size, but you don't
similarly mandate the same thing for structs and classes, then this
is an academic exercise in pedantry.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble
2015-06-16 22:47:26 UTC
Permalink
Post by legalize+ (Richard)
[Please do not mail me a copy of your followup]
Post by Scott Lurndal
Granted most of that code ran sans OS (it was the OS), and required
fixed types to map to various hardware registers.
This is the situation where I think the size of the data really *does*
matter and it's important to use sized types and not the implicit size
of int, long, etc. Things like structures representing byte streams
passed across the network (and you might do network-to-host byte
reordering in place on that structure), raw byte streams read from or
written to files, raw bytes transmitted between processes through
shared memory segments and so-on.
I've got some code im my open source project that doesn't use
specifically sized types for some binary file I/O and it's a mess right
because they used generic types. So I am certainly sympathetic to
cases where it matters.
My assertion is that it simply doesn't matter in *every* case.
Post by Scott Lurndal
However, absent API requirements for other types, I would prefer
using types for which I understand the characteristics in all
conditions, thus I prefer the explicitly sized types. Having
run into many issues in the past porting software from 16-bit
ints to 32-bit ints (and from 32-bit longs to 64-bit longs),
I would never advocating using 'int' for anything.
Here, I disagree. The size of every int in a program isn't a
portability concern. What's important is deciding which variables need
specific sizes and which don't.[*]
I've seen code where the compiler's default size of an int was 16-bits
and everywhere they wanted to iterate over containers or whatnot it was
int16_t all over the place. Then you move to a compiler where the
defaault size of an int is 32-bits. The fact that all those ints were
marked as 16-bits is now erroneous and simply a distraction. How do
you know which ones really needed to be 16-bits and which were 16-bits
simply because that was the default size of an int? Forcing them all
into a 16-bit straight jacket impedes portability instead of enhancing
it.
This is why you should design things properly perhaps by the use of a
traits class specialized for different hardware which has its own public
typedefs:

template <typename HardwareType>
struct foo_traits;

template <>
struct foo_traits<ZXSpectrum48K>
{
typedef uint16_t index_type;
};

typedef foo_traits<ZXSpectrum48K>::index_type index_type;

/* use index_type rather than uint16_t directly. */

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Chris M. Thomasson
2015-06-16 21:03:23 UTC
Permalink
Post by Mr Flibble
[...]
You are speaking for a lot of people there. As far as code reviews are
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
Programming a warplane, anyone?:

http://www.stroustrup.com/JSF-AV-rules.pdf

;^)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mr Flibble
2015-06-16 22:47:48 UTC
Permalink
Post by Chris M. Thomasson
Post by Mr Flibble
[...]
You are speaking for a lot of people there. As far as code reviews are
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
http://www.stroustrup.com/JSF-AV-rules.pdf
From that document (relevant to this thread):

AV Rule 209 (MISRA Rule 13, Revised)
The basic types of int, short, long, float and double *shall not* be
used, but specific-length
equivalents should be typedef'd accordingly for each compiler, and these
type names used in
the code.
Rationale: Since the storage length of types can vary from compiler to
compiler and
platform-to-platform, this rule ensures that code can be easily
reconfigured for storage size
differences by simply changing definitions in one file. See AV Rule 209
in Appendix A for
additional details.
Exception: Basic types are permitted in low-level routines to assist in
the management of
word alignment issues (e.g. memory allocators).
MISRA rule was changed from should to shall.

/Flibble
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
pip010
2015-08-03 12:54:29 UTC
Permalink
{ quoted server banner redacted. lines wrapped to fit
in ~70 characters. -mod }
Post by Mr Flibble
Post by Chris M. Thomasson
Post by Mr Flibble
[...]
You are speaking for a lot of people there. As far as code reviews are
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
http://www.stroustrup.com/JSF-AV-rules.pdf
AV Rule 209 (MISRA Rule 13, Revised)
The basic types of int, short, long, float and double *shall not* be
used, but specific-length
equivalents should be typedef'd accordingly for each compiler, and these
type names used in
the code.
Rationale: Since the storage length of types can vary from compiler to
compiler and
platform-to-platform, this rule ensures that code can be easily
reconfigured for storage size
differences by simply changing definitions in one file. See AV Rule 209
in Appendix A for
additional details.
Exception: Basic types are permitted in low-level routines to assist in
the management of
word alignment issues (e.g. memory allocators).
MISRA rule was changed from should to shall.
/Flibble
but this MISRA rule makes no sense. Why should you have one file
defining every type that needs to change for each new
platform/compiler ?? Isnt that the whole point of using a compiler
with agnostic type to be defined by it?
By manually doing its job the advice sounds ill to me leading to
err-prone solution. I see how fixed size types can be useful for
embedded/low level routines but for app dev? I rather say no!
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
m***@acm.org
2015-08-03 16:01:40 UTC
Permalink
{ quoted moderator comment redacted.
lines wrapped to ~70 characters. -mod }
Post by pip010
Post by Mr Flibble
Post by Chris M. Thomasson
Post by Mr Flibble
[...]
You are speaking for a lot of people there. As far as code reviews are
concerned the MISRA C++ coding standard for safey critical systems
prohibits the use of basic numerical types and mandates the use of the
typedefs from <cstdint> (or an equivalent).
http://www.stroustrup.com/JSF-AV-rules.pdf
AV Rule 209 (MISRA Rule 13, Revised)
The basic types of int, short, long, float and double *shall not* be
used, but specific-length
equivalents should be typedef'd accordingly for each compiler, and these
type names used in
the code.
Rationale: Since the storage length of types can vary from compiler to
compiler and
platform-to-platform, this rule ensures that code can be easily
reconfigured for storage size
differences by simply changing definitions in one file. See AV Rule 209
in Appendix A for
additional details.
Exception: Basic types are permitted in low-level routines to assist in
the management of
word alignment issues (e.g. memory allocators).
MISRA rule was changed from should to shall.
/Flibble
but this MISRA rule makes no sense. Why should you have one file
defining every type that needs to change for each new
platform/compiler ?? Isnt that the whole point of using a compiler
with agnostic type to be defined by it?
By manually doing its job the advice sounds ill to me leading to
err-prone solution. I see how fixed size types can be useful for
embedded/low level routines but for app dev? I rather say no!
MISRA is the Motor Industry Software Reliability Association. So you
would seem to agree the rule makes sense in its context. As with any
rule, blind application in every case does not yield the best results.

Randy.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper
2015-06-16 03:04:07 UTC
Permalink
On 06/15/2015 04:54 PM, Francis Glassborow wrote:
...
Post by Francis Glassborow
Not really, the idea was to allow systems that had more types available
over and above those required by the standard to allow programmers to
express their needs. And the rationale was a purely C one and I doubt
that it would be in C++ other than for compatibility reasons.
I don't see that. What features of the rationale for the size-named
types are C specific? I see the desire to minimize either memory use or
processing time (and to have some control over which one is minimized)
as being pretty much universal, and especially so in lower-level
languages like C and C++.
Post by Francis Glassborow
For example it is possible that on a particular platform a 32-bit
integer type performs faster than a 16-bit one. However that has a smell
of premature optimisation.
I don't see how it could be. If that's premature, when is "maturity" to
be achieved? That is, when should the decision be made to choose a type
based upon it's speed rather than it's size (or vice versa)?
Post by Francis Glassborow
In reality very few if any programmers have ever made use of those
extended types, and where they have, they are often not portable (there
is no guarantee that any of the exact types exist on a platform)
I am mainly interested in the least- and fast-sized types, which are
guaranteed, so that's not a problem for me. And, in the rare
circumstance where I'd want to use an exact-sized type, the fact that I
decided to use it would imply, correctly, that the program would be
completely irrelevant to any platform which didn't support that type:
for instance, to implement the interface to hardware that, if attached
to a given system, necessarily implies that the exact-sized type must be
supported.

Note: I expect many people to use exact-sized types inappropriately,
under circumstances were that wouldn't be true - but it's not something
I would do.
--
James Kuyper


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
James Kuyper
2015-06-15 21:55:34 UTC
Permalink
...
Post by Mr Flibble
'int' is only guaranteed to be at least 16 bits but the actual problem
is the *at least* part: it can mean *different* sizes and value ranges
on *different* implementations resulting in *different* or even
*dangerous behaviour*. If you want a type that behaves like 'int' then
And how is that different from int_fast16_t?
Post by Mr Flibble
you should be explicit about it in your code by using 'int_fast16_t' but
absolute care must be taken when using such variable types.
Please show code which uses 'int' when you think it should be using
'int_fast16_t', and explain the circumstances under which such code is
dangerous.

...
Post by Mr Flibble
Post by Francis Glassborow
If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)
You should be writing code such that the underlying type doesn't
actually matter; that is part of the rationale for <cstdint> in the
first place.
It is quite feasible to write code using short int, int, and long int,
where the underlying type doesn't actually matter. I have no objections
to <cstdint>, and would in fact have preferred it if C/C++ had adopted
types with such definitions from the very beginning, rather than adding
them on later. However, you exaggerate the problem when you claim that
that the older type names should never be used.
--
James Kuyper


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
David Brown
2015-06-16 13:04:59 UTC
Permalink
Post by Francis Glassborow
Post by David Brown
Post by Mr Flibble
Post by Mr Flibble
In modern C++ we should avoid using 'int' and its associates such as
'short' and 'long' as they are all non-portable and unsafe (their size
and value range can differ from one implementation to the next);
instead
Post by Mr Flibble
one should use the typedefs from <cstdint> instead.
Sorry, int is extremely portable, every C and C++ implementation has it
and it is guaranteed to work in a pretty large range (the actual range
can be checked quite easily via std::numeric_limits, BTW).
This all comes down to what is meant by "portable". An integer type has
several characteristics, such as availability, minimum range, size, etc.
For some of these, "int" is highly portable - it is found on any C++
system, and is guaranteed a minimum range of -32767 to +32767. But
other characteristics, such as its actual size, lack portability.
"int32_t" (and friends) on the other hand do not exist on all systems -
but when they /do/ exist, they give you cross-target portability
guarantees on size and range that you cannot get with plain "int".
If you need some or all of the additional characteristics of int32_t,
then int32_t is the most portable way to get that. If you just want a
counter or index, with a range up to +/- 32767, then "int" is the most
portable choice.
We should use the most appropriate type for the task in hand (which
could well be "auto") - sometimes it is "int", sometimes it is "int32_t".
Personally, I have very little use of "short" or "long", however.
So both C and C++ provide an integer type that is guaranteed to be at
least 32-bits, so why would I not use that when I need a 32-bit integer?
That is why int32_t better? Note that on systems with 32-bit int, long
int is usually also 32 bits.
There are a few reasons to prefer int32_t to long. One is that when you
need 32 bits, it is no bigger than necessary - long is 64-bit on many of
the most common systems these days (such as most 64-bit *nix systems -
in particular, 64-bit Linux and BSD on x86-64).

Another is that it says exactly what you mean - it is absolutely clear
in the code that you picked that type because you wanted 32 bits. You
didn't just use a "long" because you thought the data might be a bit
big, or because you guessed a particular size for "long", or because
your code has ancestry back to 16-bit Windows and used "long" to hold
pointers.
Post by Francis Glassborow
And where I need 64 bits the (ugly) long long int meets my need.
Yes, but "long long int" is /ugly/ ! And again, int64_t says exactly
what you mean.
Post by Francis Glassborow
If I use real types I do not have to worry about places where the
behaviour varies according to the underlying type (most commonly i/o in C)
I agree that short is pretty useless these days. It would have made more
sense if it had been an exact 16-bit integer type.
Francis
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Öö Tiib
2015-06-27 20:17:13 UTC
Permalink
Post by Mr Flibble
The fact we have to do this is due to shortcoming of the current C++
auto i = 42s32; // signed, 32-bits
Adding that would look like garbage but that is matter of taste
perhaps. However it may be deceptive:

auto i = -666s16;

Type of 'i' will be 'signed int' on most platforms.

In real code we do not have that problem since we do not use the
'auto' keyword for naming the integral constants (and that we do
to avoid magic numbers in code):

constexpr int32_t NumberOfAntiBeast = -666;

Note that here we do not need your s32 suffix for anything.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Continue reading on narkive:
Loading...