On 12/26/2015 1:54 AM, Ramine wrote:
>
> I was working on a project in C++, but i have encountered
> a problem with the language that we call C++, this problem
> is inherent to C++ and C, here is a small example that
> shows the problem:
>
> ===
>
> #include <iostream>
> using namespace std;
>
> int main()
> {
> unsigned int u = 1234;
> int i = -1233;
>
> unsigned int result1 = u + i;
> std::cout << "Number is = " << result1 << std::endl;
> }
>
> ==
>
>
> In this example, C++ and C will convert i from a signed int type to
> unsigned int type but this is not good , because this types of
> conversion can cause bugs and errors of logic
No, only ignorance about the implicit conversion to unsigned can cause
problems for this specific code. The above result is well-defined
because any conversion of integer to unsigned integer is defined as
yielding the result modulo 2^n where n is the number of value
representation bits in the unsigned type. And it's an expected result.
However, there is a closely related feature, namely implicit PROMOTION
up to unsigned in an expression with mixed type operands, where the
above conversion is invoked, that can cause trouble. Specifically, if
integer types Signed and Unsigned have the same size, or Unsigned is
larger than Size, and if such values occur as operands to some built-in
operator, then the Signed value is implicitly converted to Unsigned.
Which is well-defined but can yield nonsense results such as
`string("blah").length() < -5` evaluating to `true`.
For more and more specific information about the implicit conversions in
expressions, look up the "usual arithmetic conversions".
• • •
Recommendations: I recommend using signed integers for numbers and using
unsigned only for bitlevel things. That avoids the surprising automatic
promotions and related bugs, plus, it avoids the common and annoying
warnings about comparing signed and unsigned. Where you need to indicate
that an integer is non-negative, simply use a type alias such as
"Nonnegative", or better, some name specific to the use.
• • •
To do that, you will in practice need non-member `size` functions that
produce signed integer results, like `static_size`, `n_items` and
`length` below:
using Size = ptrdiff_t;
// Static capacity of a collection.
template< class Type, Size n >
auto constexpr static_size( Ref_<Type[n]> )
-> Size
{ return n; }
template< class Type, Size n >
auto constexpr static_size( Ref_<const std::array<Type, n>> )
-> Size
{ return n; }
template< Size n >
auto constexpr static_size( Ref_<const std::bitset<n>> )
-> Size
{ return n; }
// Right-typed (signed integer) dynamic size of a collection.
template< class Type >
auto n_items( Ref_<const Type> o )
-> Size
{ return o.size(); }
template< Size n >
auto n_items( Ref_<const std::bitset<n>> o )
-> Size
{ return o.count(); } // Corresponds to std::set<int>::size()
// Lengths of strings.
template< class Char, Size n >
auto constexpr length_of_literal( Ref_<const Char[n]> ) //
"length" wraps this.
-> Size
{ return n - 1; }
template< class Char, class Traits, class Alloc >
auto length( Object_argument, Ref_<const std::basic_string<Char,
Traits, Alloc>> s )
-> Size
{ return s.length(); }
template< class Char >
auto length( Pointer_argument, const Ptr_<const Char> s )
-> Size
{
auto p = s;
while( *p != 0 ) { ++p; }
return p - s;
}
template< class Char, Size n
, class Enabled_ = If_< In_< Character_types, Char > >
>
auto constexpr length( Array_argument, Ref_<const Char[n]> a )
-> Size
{ return length_of_literal( a ); }
template< class Type >
auto length( Ref_<const Type> o )
-> Size
{ return length( Arg_kind_<Type>(), o ); }
The above code is available at GitHub along with other such core
language support, as I recently announced in this group -- but while
that code works with Visual C++ it's not yet even been compiled with
g++, and some of it is only at the 1% to 2% state of completion:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4280
In C++1z (C++17?) some of the above functions can and probably for
clarity should be expressed in terms of the new `std::size` non-member
function. However, that function is generally unsigned and conflates the
`static_size` and `n_items` functions above, which means that the
wrappers will still be needed, unless the proposal is fixed. See
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4280
for more detailed info.
> , so i think we must
> forbid C and C++ on realtime critical systems... and i have read on
> internet that C and C++ are strongly typed languages, how can you
> say that !
C is not strongly typed in any sense.
C++ supports, but does not require, strongly typed code.
Betrand Meyer, in his Software Development book, went on at length about
the difference of /enabling/ something, versus fully /supporting/ it.
C++ enables strongly typed code, and C++ provides much support for it,
but does not require it. That has to do with its historical roots in C,
that C++ must support direct use of most C libraries.
> ingnoring the simple fact that an implicit conversion
> in C++ and C takes place between a signed int type and an unsigned int
> type for example, so that makes C and C++ problematic and not suited for
> realtime critical systems and such, ADA and Delphi and FreePascal are in
> fact strongly typed and does not authorize this type of conversion.
The problems for designing and implementing real time systems are much
to do with the dangers of parallel processing and less to do with the
low level details of the language at hand.
Well, there are of course also management problems. For an example you
might google the Ariane disaster... ;-)
Now that C++ supports threads in its standard library it's perhaps even
better suited for real time systems. Still I think very fondly of the
Ada rendezvous mechanism for threads. I don't think that can be easily
emulated (at least not efficiently) in C++!
Cheers & hth.,
- Alf