Discussion:
[Audacity-devel] the use of unsigned
David Bailes
2016-09-19 14:04:19 UTC
Permalink
Paul has been changing quite a few variables from int to unsigned int.
I appreciate that there are differing views on where unsigned ints should
be used, but given the lack of automated testing in Audacity, I think that
there's a danger that these changes may introduce bugs.

As I said, there are views on either side, but these are a couple of links
to those of Stroustrup. My summary of his view is: because the result of
mixing signed and unsigned is often unexpected and can lead to bugs, only
use unsigned where really necessary, eg bit manipulation.

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#user-content-arithmetic

And this video from about 43mins:
https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything

David.
Paul Licameli
2016-09-19 14:14:28 UTC
Permalink
Post by David Bailes
Paul has been changing quite a few variables from int to unsigned int.
I appreciate that there are differing views on where unsigned ints should
be used, but given the lack of automated testing in Audacity, I think that
there's a danger that these changes may introduce bugs.
As I said, there are views on either side, but these are a couple of links
to those of Stroustrup. My summary of his view is: because the result of
mixing signed and unsigned is often unexpected and can lead to bugs, only
use unsigned where really necessary, eg bit manipulation.
I don't know if that is a fair summary, I don't deduce "use unsigned only
for these things" from those two things.

The danger is mixed arithmetic, and we can get compilers to emit warnings
about that.

PRL
Post by David Bailes
https://github.com/isocpp/CppCoreGuidelines/blob/master/
CppCoreGuidelines.md#user-content-arithmetic
https://channel9.msdn.com/Events/GoingNative/2013/
Interactive-Panel-Ask-Us-Anything
David.
------------------------------------------------------------
------------------
_______________________________________________
audacity-devel mailing list
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Roger Dannenberg
2016-09-19 14:50:04 UTC
Permalink
Stroustrup is first author on the first link, which says:


ES.100: Don't mix signed and unsigned arithmetic

That seems pretty clear to me. Compilers can give warnings, but if
humans can't understand the code that's warned about, how does that
help? (E.g. I could not guess the results of the examples in the text.)
I think you have to look at every case separately, but if you need
unsigned because 31 bits is not enough, but 32 /is/ enough, maybe the
code would be more maintainable just using a 64-bit signed integer.

-Roger
Post by David Bailes
Paul has been changing quite a few variables from int to unsigned int.
I appreciate that there are differing views on where unsigned ints
should be used, but given the lack of automated testing in
Audacity, I think that there's a danger that these changes may
introduce bugs.
As I said, there are views on either side, but these are a couple
because the result of mixing signed and unsigned is often
unexpected and can lead to bugs, only use unsigned where really
necessary, eg bit manipulation.
I don't know if that is a fair summary, I don't deduce "use unsigned
only for these things" from those two things.
The danger is mixed arithmetic, and we can get compilers to emit
warnings about that.
PRL
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#user-content-arithmetic
<https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#user-content-arithmetic>
https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything
<https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything>
David.
------------------------------------------------------------------------------
_______________________________________________
audacity-devel mailing list
https://lists.sourceforge.net/lists/listinfo/audacity-devel
<https://lists.sourceforge.net/lists/listinfo/audacity-devel>
------------------------------------------------------------------------------
_______________________________________________
audacity-devel mailing list
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Paul Licameli
2016-09-19 15:17:30 UTC
Permalink
What is the type of s + u where s is int and u is unsigned?

The answer is unsigned -- though the conversions of signed to unsigned and
back are "narrowing" each way. (Meaning, each type has values that the
other cannot represent.)

That can be deduced from the conversion rules on this page, which are worth
getting acquainted with:

http://en.cppreference.com/w/cpp/language/operator_arithmetic#Additive_operators

Unsigned arithmetic is arithmetic modulo some power of n, usually n = 32.

I have a preference for use of unsigned types, not where an extra bit of
width is needed, but rather to make it clear by use of the type system that
negative values are not allowed as arguments and will not be returned. But
then you must examine subtractions very carefully.

Whereas my examination of sampleCount really was about width too. 64 bits
is appropriate to describe positions in audio streams which could
reasonably have more than 2^31 samples -- hours long but not many hours.
Yet size_t describes a buffer that gives limited computer memory a window
into that stream. I examined all the over-use of sampleCount to be sure
there were not any suspect narrowings. sampleCount now gets converted to
size_t only where difference of two sample counts are taken, and there is
some informal proof (commented) that the result is small and not negative.

PRL
Post by Roger Dannenberg
ES.100: Don't mix signed and unsigned arithmetic
That seems pretty clear to me. Compilers can give warnings, but if humans
can't understand the code that's warned about, how does that help? (E.g. I
could not guess the results of the examples in the text.) I think you have
to look at every case separately, but if you need unsigned because 31 bits
is not enough, but 32 *is* enough, maybe the code would be more
maintainable just using a 64-bit signed integer.
-Roger
Post by David Bailes
Paul has been changing quite a few variables from int to unsigned int.
I appreciate that there are differing views on where unsigned ints should
be used, but given the lack of automated testing in Audacity, I think that
there's a danger that these changes may introduce bugs.
As I said, there are views on either side, but these are a couple of
links to those of Stroustrup. My summary of his view is: because the result
of mixing signed and unsigned is often unexpected and can lead to bugs,
only use unsigned where really necessary, eg bit manipulation.
I don't know if that is a fair summary, I don't deduce "use unsigned only
for these things" from those two things.
The danger is mixed arithmetic, and we can get compilers to emit warnings
about that.
PRL
Post by David Bailes
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC
oreGuidelines.md#user-content-arithmetic
https://channel9.msdn.com/Events/GoingNative/2013/Interactiv
e-Panel-Ask-Us-Anything
David.
------------------------------------------------------------
------------------
_______________________________________________
audacity-devel mailing list
https://lists.sourceforge.net/lists/listinfo/audacity-devel
------------------------------------------------------------------------------
_______________________________________________
------------------------------------------------------------
------------------
_______________________________________________
audacity-devel mailing list
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Richard Ash
2016-09-19 21:59:26 UTC
Permalink
On Mon, 19 Sep 2016 10:50:04 -0400
Post by Roger Dannenberg
ES.100: Don't mix signed and unsigned arithmetic
That seems pretty clear to me. Compilers can give warnings, but if
humans can't understand the code that's warned about, how does that
help?
Remember that size_t is an unsigned type. So the corollary of
Stroustrup's guidance is that all arithmetic which uses size_t should
be unsigned.
Post by Roger Dannenberg
From my work background (semi-embedded industrial) I would question any
code which does an unchecked conversion between a wider (at either end)
type and a narrower type. Any conversion involving signed and
unsigned values of the same width loses at one end or the other, so
there needs to be a check at the conversion. Locating these is a very
good use of the compiler warning, and once the check exists, an
explicit cast gets rid of the warning, and makes the conversion obvious
to anyone reading the code.

So as far understanding goes, any use of intentional overflow / modulo
arithmetic needs comments to explain it anyway, and certainly should
use consistent type. In C++ code for multiple platforms I would regard
that sort of trick as inappropriate anyway - it belongs to
single-target microcontroller code in base C.
Post by Roger Dannenberg
I think you have to look at every case separately, but if you
need unsigned because 31 bits is not enough, but 32 /is/ enough,
maybe the code would be more maintainable just using a 64-bit signed
integer.
If range is the only consideration, and you are free to choose the
types (no libraries involved) then I would agree. However once you
start using libaries which have APIs defined in terms of size_t, that
flexibility is lost (although size_t may well be an unsigned 64-bit int
in some cases ...)

On Mon, 19 Sep 2016 11:17:30 -0400
Post by Roger Dannenberg
sampleCount now gets converted to size_t only where difference of two
sample counts are taken, and there is some informal proof (commented)
that the result is small and not negative.
With my work hat on, I'd be giving you a hard time about this. I would
normally want either an assert or a runtime error handler on this sort
of conversion. I haven't reviewed the actual commits, but I have spent a
lot of time with bugs caused by things that 'won't happen'.

Richard

------------------------------------------------------------------------------
Paul Licameli
2016-09-19 22:14:47 UTC
Permalink
Post by Richard Ash
On Mon, 19 Sep 2016 10:50:04 -0400
Post by Roger Dannenberg
ES.100: Don't mix signed and unsigned arithmetic
That seems pretty clear to me. Compilers can give warnings, but if
humans can't understand the code that's warned about, how does that
help?
Remember that size_t is an unsigned type. So the corollary of
Stroustrup's guidance is that all arithmetic which uses size_t should
be unsigned.
Indeed, one might, pedantically, add 1u not 1, say, wherever you combine it
with a constant.
Post by Richard Ash
Post by Roger Dannenberg
From my work background (semi-embedded industrial) I would question any
code which does an unchecked conversion between a wider (at either end)
type and a narrower type.
And yes, my sweep of uses of 64 bit sampleCount used as the size of an
in-memory buffer, was all about suspicious narrowing conversions.
Post by Richard Ash
Any conversion involving signed and
unsigned values of the same width loses at one end or the other, so
there needs to be a check at the conversion. Locating these is a very
good use of the compiler warning, and once the check exists, an
explicit cast gets rid of the warning, and makes the conversion obvious
to anyone reading the code.
The clang compiler with XCode can provide this, if you change some settings
for the Audacity project file. I am busy trying to sweep the warnings
right now. Many of which come from lib-src though.

But -- habitual casting only papers over the problem and should be
discouraged. I think that wherever casting happens, there should be at
least a comment explaining why the conversion is justified, or more
strongly an assertion. You should be able to prove from the context that
the narrowed value will not be out of bounds.
Post by Richard Ash
So as far understanding goes, any use of intentional overflow / modulo
arithmetic needs comments to explain it anyway, and certainly should
use consistent type. In C++ code for multiple platforms I would regard
that sort of trick as inappropriate anyway - it belongs to
single-target microcontroller code in base C.
Post by Roger Dannenberg
I think you have to look at every case separately, but if you
need unsigned because 31 bits is not enough, but 32 /is/ enough,
maybe the code would be more maintainable just using a 64-bit signed
integer.
If range is the only consideration, and you are free to choose the
types (no libraries involved) then I would agree. However once you
start using libaries which have APIs defined in terms of size_t, that
flexibility is lost (although size_t may well be an unsigned 64-bit int
in some cases ...)
Libraries? It's not just about third party libraries. size_t is baked
into the language itself, as the type passed to operator new, and also
baked into the standard C++ library.
Post by Richard Ash
On Mon, 19 Sep 2016 11:17:30 -0400
Post by Roger Dannenberg
sampleCount now gets converted to size_t only where difference of two
sample counts are taken, and there is some informal proof (commented)
that the result is small and not negative.
With my work hat on, I'd be giving you a hard time about this. I would
normally want either an assert or a runtime error handler on this sort
of conversion. I haven't reviewed the actual commits, but I have spent a
lot of time with bugs caused by things that 'won't happen'.
See what I have done to sampleCount. It is now a class, not just an alias
for 64 bit integer. It does not convert implicitly to numerical types, but
compels you to call a member function called as_double, as_float,
as_long_long, or as_size_t. And the last does assert dynamically that the
conversion is within bounds, at least in debug builds.

PRL
Post by Richard Ash
Richard
------------------------------------------------------------
------------------
_______________________________________________
audacity-devel mailing list
https://lists.sourceforge.net/lists/listinfo/audacity-devel
Loading...