Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > casting unsigned integers

Reply
Thread Tools

casting unsigned integers

 
 
techie
Guest
Posts: n/a
 
      10-12-2006
I have defined a number of unsigned integer types as follows:

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedfe long long uint64;

Is it necessary to explicitly cast from one type of unsigned integer type to
another even though they do so implicitly?

e.g. bytes0_1 |= (static_cast<uint16>(VersionNo)) << 12;

bytes0_1 is of type uint16. Here I thought it is safer to cast VersionNo
(type uint to uint16 before I do a left shift. I was just a bit worried
about shifting the digits off the end of an 8 bit number. Likewise in the
statement below I cast the result of the left shift and bit wise addition to
uint64.

byte6 = static_cast<uint8>((MAC_Adddress >> 40) & 0xFF);

MAC_Adddress is of type uint64.

When I run QA C++ (source code analyzer) on my code it issues a few warnings
for the first statement:

Bitwise operator is being applied to a signed type.
This is an implicit conversion between signed and unsigned integer types.
Be aware that an implicit conversion from 'uint16' to 'int' takes place.

I think I can ignore the first two warnings as the types are actually
unsigned integers and not signed as it thinks they are. I think the third
one means that in order to do the left shift it does an implicit conversion
to int as operator << is just defined for int.

Are these static_casts necessary? Is there a better way to write these
statements?


 
Reply With Quote
 
 
 
 
Steve Pope
Guest
Posts: n/a
 
      10-12-2006
techie <(E-Mail Removed)> wrote:

>I have defined a number of unsigned integer types as follows:
>
>typedef unsigned char uint8;
>typedef unsigned short uint16;
>typedef unsigned int uint32;
>typedfe long long uint64;


>Is it necessary to explicitly cast from one type of unsigned integer type to
>another even though they do so implicitly?
>
>e.g. bytes0_1 |= (static_cast<uint16>(VersionNo)) << 12;
>
>bytes0_1 is of type uint16. Here I thought it is safer to cast VersionNo
>(type uint to uint16 before I do a left shift. I was just a bit worried
>about shifting the digits off the end of an 8 bit number. Likewise in the
>statement below I cast the result of the left shift and bit wise addition to
>uint64.
>
>byte6 = static_cast<uint8>((MAC_Adddress >> 40) & 0xFF);
>
>MAC_Adddress is of type uint64.
>
>When I run QA C++ (source code analyzer) on my code it issues a few warnings
>for the first statement:
>
>Bitwise operator is being applied to a signed type.


In your first expression the right-hand side has two operands.
The wider of these operands is the constant 12, which is
of type int, and is therefore (probably) 32 bits wide (on
many systems). The other operand, which is the expression
(static_cast<uint16>(VersionNo)), is promoted to being 32 bits
wide to match the wider operand. Then the 12 is promoted to
unsigned (if either operand is unsigned, the other becomes
unsigned). The result of the shift operation is an unsigned
int (32 bits), which is then automatically cast down to the width
of the left hand side, which is 16 bits unsigned.

I do not particularly understand why the compiler gave you this
particular warning, but it seems to derive from the implicit
promotion of the signed constant 12 to an unsigned value.

Steve
 
Reply With Quote
 
 
 
 
Jack Klein
Guest
Posts: n/a
 
      10-13-2006
On Thu, 12 Oct 2006 05:30:24 +0000 (UTC), http://www.velocityreviews.com/forums/(E-Mail Removed)
(Steve Pope) wrote in comp.lang.c++:

> techie <(E-Mail Removed)> wrote:
>
> >I have defined a number of unsigned integer types as follows:
> >
> >typedef unsigned char uint8;
> >typedef unsigned short uint16;
> >typedef unsigned int uint32;
> >typedfe long long uint64;

>
> >Is it necessary to explicitly cast from one type of unsigned integer type to
> >another even though they do so implicitly?
> >
> >e.g. bytes0_1 |= (static_cast<uint16>(VersionNo)) << 12;
> >
> >bytes0_1 is of type uint16. Here I thought it is safer to cast VersionNo
> >(type uint to uint16 before I do a left shift. I was just a bit worried
> >about shifting the digits off the end of an 8 bit number. Likewise in the
> >statement below I cast the result of the left shift and bit wise addition to
> >uint64.
> >
> >byte6 = static_cast<uint8>((MAC_Adddress >> 40) & 0xFF);
> >
> >MAC_Adddress is of type uint64.
> >
> >When I run QA C++ (source code analyzer) on my code it issues a few warnings
> >for the first statement:
> >
> >Bitwise operator is being applied to a signed type.

>
> In your first expression the right-hand side has two operands.
> The wider of these operands is the constant 12, which is
> of type int, and is therefore (probably) 32 bits wide (on
> many systems). The other operand, which is the expression
> (static_cast<uint16>(VersionNo)), is promoted to being 32 bits
> wide to match the wider operand.


No, that is not correct for the bitwise shift operators. The left and
right operands do not need to be converted to the same type.

The integer promotions would apply to the argument on the right if and
only if it were a narrower type than int. Since the plain integer
literal "12" already has type int, no change is necessary. This has
nothing at all to do with the number of bits in an int.

The cast forces a conversion "VersionNo" from unsigned char to
unsigned short. Then it is automatically converted to either int or
unsigned int. Since the OP has told us by his typedef that int has 32
bits on his platform, and a signed 32-bit int can hold all the
possible values of an unsigned 16-bit short, it is converted to signed
int, not unsigned int.

See paragraph 1 of 4.5 of the C++ standard.

> Then the 12 is promoted to
> unsigned (if either operand is unsigned, the other becomes
> unsigned).


The type of the left hand operand in bitwise shift operator
expressions has nothing at all to do with the type or any conversions
performed on the right hand operator. "12" starts out as an int and
stays an int.

There is no need to convert the two operands of the bitwise shift
operators to the same type, as they are never directly combined. The
bitwise shift binary operators are different from the arithmetic and
bitwise AND, OR, and XCR operations in this respect.

See 5.8 of the C++ standard, and note the omission of the phrase "the
usual arithmetic conversions are performed".

> The result of the shift operation is an unsigned
> int (32 bits), which is then automatically cast down to the width
> of the left hand side, which is 16 bits unsigned.


There are two errors in the paragraph above. First is the fact that
since the left hand operand of the shift operator is a signed int, the
result also has the type signed int.

It is not "automatically cast", there is no such thing. C++ has
conversions, some of which are automatic and some of which require a
cast. A cast is only performed by one of the cast operators, and
tells the compiler to perform an explicit conversion, one which might
or might not have happened automatically in the absence of the cast.

The OP did not specify the type of the destination "bytes0_1", but if
it is not signed int, the result of the shift operator is
automatically converted to that type.

> I do not particularly understand why the compiler gave you this
> particular warning, but it seems to derive from the implicit
> promotion of the signed constant 12 to an unsigned value.


There is no promotion or conversion at all of the integer literal "12"
to an unsigned value. It has type int, and it remains type int in the
expression.

The warning is because the unsigned 16-bit short promoted to a signed
32-bit int.

C++ inherits its integer promotion rules from ISO C, and those rules
are "value preserving" rather than "sign preserving".

When an unsigned integer type of lesser rank than int is being
promoted to int, it is promoted to signed int if the entire range of
values of the lesser unsigned type is within the range of positive
values in a signed int.

On an implementation with 16-bit shorts and 16-bit ints, an unsigned
short would promote to unsigned int. On an implementation with 16-bit
shorts and 32-bit ints, an unsigned short promotes to signed int.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
 
Reply With Quote
 
techie
Guest
Posts: n/a
 
      10-13-2006
I have now modified my code to the following:

uint32 sum = 0;
sum |= static_cast<utils::uint32>(MajorVer) << 12;
sum |= static_cast<utils::uint32>(MinorVer) << 4;
sum |= static_cast<utils::uint32>(Config);
uint16 bytes0_1 = static_cast<uint16>(sum);

Here MajorVer, MinorVer and Config are of type uint8. I am combining their
values into a 16 bit integer. As I am using a uint32 variable (sum) to do
the addition, which is the size of int, I get no warnings at all.

I could leave out the static_cast<utils::uint32> operations and just allow
for implicit conversion to int but PRQA gives me a maintenance warning about
that. Explicitly casting to uint32 shows the intent.



 
Reply With Quote
 
Steve Pope
Guest
Posts: n/a
 
      10-13-2006
Jack Klein <(E-Mail Removed)> wrote:

> (Steve Pope) wrote in comp.lang.c++:


>>> typedef unsigned short uint16;
>>> bytes0_1 |= (static_cast<uint16>(VersionNo)) << 12;
>>> bytes0_1 is of type uint16.


>> In your first expression the right-hand side has two operands.
>> The wider of these operands is the constant 12, which is
>> of type int, and is therefore (probably) 32 bits wide (on
>> many systems). The other operand, which is the expression
>> (static_cast<uint16>(VersionNo)), is promoted to being 32 bits
>> wide to match the wider operand.


>No, that is not correct for the bitwise shift operators. The left and
>right operands do not need to be converted to the same type.


>The integer promotions would apply to the argument on the right if and
>only if it were a narrower type than int.


Please re-read what I wrote above. I said that the operand on
the *left* is promoted to 32 bits, to match the operand on the right.
I did not in the above say the operand on the right was promoted.

>The cast forces a conversion "VersionNo" from unsigned char to
>unsigned short. Then it is automatically converted to either int or
>unsigned int. Since the OP has told us by his typedef that int has 32
>bits on his platform, and a signed 32-bit int can hold all the
>possible values of an unsigned 16-bit short, it is converted to signed
>int, not unsigned int.


>See paragraph 1 of 4.5 of the C++ standard.


See 4.7 -- "The conversions allowed as integral promotions [e.g.
in 4.5] are excluded from the set of integral conversions".
This means, I believe, that if there is a need to convert to unsigned
based on the operands of the expression, then that need has precedence
over the possibility of storing an unsigned value in a signed quantity
if there are enough bits.

(In practice, it doesn't matter since the result is the same.)

>> Then the 12 is promoted to
>> unsigned (if either operand is unsigned, the other becomes
>> unsigned).


>The type of the left hand operand in bitwise shift operator
>expressions has nothing at all to do with the type or any conversions
>performed on the right hand operator. "12" starts out as an int and
>stays an int.


>There is no need to convert the two operands of the bitwise shift
>operators to the same type, as they are never directly combined. The
>bitwise shift binary operators are different from the arithmetic and
>bitwise AND, OR, and XCR operations in this respect.


>See 5.8 of the C++ standard, and note the omission of the phrase "the
>usual arithmetic conversions are performed".


I'll agree this could be interpreted to mean that shift operators
are treated differently from other arithmetic operators in terms
of forcing conversions to unsigned, but it doesn't really say
this explicitly.

>> The result of the shift operation is an unsigned
>> int (32 bits), which is then automatically cast down to the width
>> of the left hand side, which is 16 bits unsigned.


>There are two errors in the paragraph above. First is the fact that
>since the left hand operand of the shift operator is a signed int,


That is true is your first argument above is correct, and I'm
not yet convinced.

>It is not "automatically cast", there is no such thing. C++ has
>conversions, some of which are automatic and some of which require a
>cast. A cast is only performed by one of the cast operators, and
>tells the compiler to perform an explicit conversion, one which might
>or might not have happened automatically in the absence of the cast.


Okay, my terminology was incorrect there.

>The OP did not specify the type of the destination "bytes0_1"


Yes, he did, see quoted text above.

>if it is not signed int, the result of the shift operator is
>automatically converted to that type.


Yes, and it is converted. (But not "automatically cast" as you
point out.)

>C++ inherits its integer promotion rules from ISO C, and those rules
>are "value preserving" rather than "sign preserving".


Is this something that changed between K&R C and ISO C? The
rules in K&R section 2.7, "Type conversions" are as I describe,
and it is my belief that you will never get a different result
in C++ than these rules would imply, even if the C++ rules are
a bit different in some intermediate details.

Thanks for you post.

Steve
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
(int) -> (unsigned) -> (int) or (unsigned) -> (int) -> (unsigned):I'll loose something? pozz C Programming 12 03-20-2011 11:32 PM
Casting from const pair<const unsigned char*, size_t>* to constpair<unsigned char*, size_t>* Alex Vinokur C++ 9 10-13-2008 05:05 PM
Adding and multiplying two unsigned integers Edith Gross C++ 5 05-01-2005 04:48 PM
8-bit unsigned integers in Java jeff Java 2 03-07-2004 06:10 PM
Casting integers to float. Jonathan Fielder C Programming 8 08-13-2003 09:20 PM



Advertisments