8

The -Wconversion GCC parameter produces the warning from the title when compiling this program:

#include <iostream>
#include <array>
#include <string>

int main ()
{
    std::string test = "1";
    std::array<unsigned char, 1> byteArray;

    byteArray[0] = byteArray[0] | test[0];

    return 0;
}

Here is how I compile it: g++- -Wall -Wextra -Wconversion -pedantic -std=c++0x test.cpp and I'm using GCC 4.5.

Am I doing something illegal here? Can it cause problems in certain scenarios? Why would the | produce an int?

1
  • 4
    +1 for a complete, concise example program. sscce.org. Commented Aug 20, 2012 at 14:28

3 Answers 3

6

Am I doing something illegal here?

You're converting from a signed type to an unsigned type. If the signed value were negative, then the unsigned result would be an implmentation-defined non-negative value (and therefore not the same as the initial value).

Can it cause problems in certain scenarios?

Only if the value might be negative. That might be the case on somewhat exotic architectures where sizeof (char) == sizeof (int), or if your code were doing something more complicated than combining two values with |.

Why would the | produce an int?

Because all integer values are promoted before being used in arithmetic operations. If their type is smaller than int, then they are promoted to int. (There's somewhat more to promotion than that, but that's the rule that's relevant to this question).

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Mike! So, the fix would be to explicitly cast test[0] to unsigned char as well as the result of |?
cast test[0] to unsigned char BEFORE. bytearray[0] | (unsigned char)test[0]
2

yes, a string is made up of char which is signed, you have an array of unsigned char.

as for as | producing an int, it's called integer promotion. basically the compiler makes them both ints, does a |, then makes them char's again.

It runs into a problem though. By the C/C++ standards, integer promotion happens if the type promoted to can hold all values of the type promoted from. so it promotes the unsigned char to an unsigned int and the signed char to a signed int. Promotion of a signed value sign-extends it. So say you have -1 or 0xFF or 11111111. That is extended to 10000000000000000000000001111111 signed int ((int)-1). Obviously that will have a different result than |'ing with 11111111 ((char)-1) would intuitively expect.

See here for more info: here it explains a sort of 'workaround'

7 Comments

True but only marginally related to the question.
@KonradRudolph yet it is the root of the problem...oh well
Not to speak of the fact that char doesn't even have to be signed.
I’ll take that back, the warning disappears when both char containers use the same char type. Integer promotion obviously still happens (hence my initial comment, at that time the answer didn’t mention integer promotion) but the warning disappears.
that is not how -1 gets extended in twos-compliment. In twos-compliment, -1 is all ones.
|
2

Result of unsigned char | char is int per integer conversion rules. When you assign int back to unsigned char, assignment can truncate its int value - compiler does not know what how big the value you have in this int.

To silence the compiler:

byteArray[0] = static_cast<unsigned char>(byteArray[0] | test[0]);

2 Comments

OK, I see... So how would you implement this in order to avoid the problem?
byteArray[0] = static_cast<unsigned char>(byteArray[0] | test[0]);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.