casting unsigned integers

Discussion in 'C++' started by techie, Oct 12, 2006.

  1. techie

    techie Guest

    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 uint8) 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

    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
    techie, Oct 12, 2006
    1. Advertisements

  2. techie

    Steve Pope Guest

    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 Pope, Oct 12, 2006
    1. Advertisements

  3. techie

    Jack Klein Guest

    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.
    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".
    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.
    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

    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, Oct 13, 2006
  4. techie

    techie Guest

    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.
    techie, Oct 13, 2006
  5. techie

    Steve Pope Guest

    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.
    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.)
    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.
    That is true is your first argument above is correct, and I'm
    not yet convinced.
    Okay, my terminology was incorrect there.
    Yes, he did, see quoted text above.
    Yes, and it is converted. (But not "automatically cast" as you
    point out.)
    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 Pope, Oct 13, 2006
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.