18

Consider following code:

void foo(unsigned int x)
{

}

int main()
{
  foo(-5);
  return 0;
}

This code compiles with no problems. Errors like this can cause lots of problems and are hard to find. Why does C++ allow such conversion?

user438383
  • 5,716
  • 8
  • 28
  • 43
Nefarel NefX
  • 181
  • 1
  • 3
  • 7
    Trite answer: because C++ was designed to be (mostly) backwards-compatible with C, and C allows implicit casts between integral types. – user168715 Mar 10 '11 at 17:20
  • 2
    Interestingly, most compilers give warning if you compare `int` with `unsigned int`, like in `i < ui` – Nawaz Mar 10 '11 at 17:21
  • @user168715: that doesn't make sense. Warning doesn't mean it doesn't allow you. It merely means there might be some problem in implicit conversion! – Nawaz Mar 10 '11 at 17:22
  • @Nawaz: Yea. Comparing and converting are not the same thing. – Lightness Races in Orbit Mar 10 '11 at 17:22
  • @Nawaz: What are you on about? user168715 never spoke of warnings. – Lightness Races in Orbit Mar 10 '11 at 17:22
  • @Tomalak: I didn't say it's same thing. But if there can be problem in comparing, there can be problem in implicit conversion too. And we know these often cause problem! – Nawaz Mar 10 '11 at 17:23
  • @Tomalak: He did implicitly, since his comment starts with *"because..."* to a question on *"why warning"* – Nawaz Mar 10 '11 at 17:25
  • You can setup your environment to treat this warning as an error to help catch it but in perfect code you would not be using implicit casting at all, right? – AJG85 Mar 10 '11 at 17:26
  • @Nawaz: I don't see where the question says "_why warning_". – Lightness Races in Orbit Mar 10 '11 at 17:28
  • 3
    @Nawaz: The question is "Why [does] C++ allow such conversion"; "warning" appears nowhere in the original title or question. – user168715 Mar 10 '11 at 17:29
  • And if your environment can't catch it then take a look at a static analysis tool like PC-Lint. – GrahamS Mar 10 '11 at 17:31
  • 7
    People, Nawaz made an interesting observation, not an attempted explanation. Cool your jets. – Matt K Mar 10 '11 at 17:36
  • @Tomalak: common, I can understand that "with the correct config compilers warn" is not an answer to the question, but I find it to be a reasonable *comment*: it is dangerous, it is accepted, but can be detected. – David Rodríguez - dribeas Mar 10 '11 at 18:22
  • @dribeas: Absolutely. I was trying to resolve the confusion because he was answering a question that was not asked. I'm not saying that his observation was wrong; it was just a complete conversational _non sequitur_. – Lightness Races in Orbit Mar 11 '11 at 01:04

5 Answers5

21

The short answer is because C supported such conversions originally and they didn't want to break existing software in C++.

Note that some compilers will warn on this. For example g++ -Wconversion will warn on that construct.

In many cases the implicit conversion is useful, for example when int was used in calculations, but the end result will never be negative (known from the algorithm and optionally asserted upon).

EDIT: Additional probable explanation: Remember that originally C was a much looser-typed language than C++ is now. With K&R style function declarations there would have been no way for the compiler to detect such implicit conversions, so why bother restricting it in the language. For example your code would look roughly like this:

int foo(x)
unsigned int x
{

}

int main()
{
  foo(-5);
  return 0;
}

while the declaration alone would have been int foo(x);

The compiler actually relied on the programmer to pass the right types into each function call and did no conversions at the call site. Then when the function actually got called the data on the stack (etc) was interpreted in the way the function declaration indicated.

Once code was written that relied on that sort of implicit conversion it would have become much harder to remove it from ANSI C even when function prototypes were added with actual type information. This is likely why it remains in C even now. Then C++ came along and again decided to not break backwards compatibility with C, continuing to allow such implicit conversions.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    For MSVC, enable 4365 "signed/unsigned mismatch" to enable checking for this, it's been helpful for my code. – moltenform Oct 02 '16 at 05:39
7
  • Just another quirk of a language that has lots of silly quirks.
  • The conversion is well-defined to wrap around, which may be useful in some cases.
  • It's backward-compatible with C, which does it for the above reasons.

Take your pick.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
4

@user168715 is right. C++ was initially designed to be a superset of C, pretending to be as backward-compatible as possible. The "C" philosophy is to deliver most of the responsibility to the programmer, instead of disallowing dangerous things. For C programmers it is heaven, for Java programmers, it is hell... a matter of taste.

I will dig the standards to see where exactly it is written, but I have no time for this right now. I'll edit my answer as soon as I can.

I also agree that some of the inherited freedom can lead to errors that are really hard to debug, so I am adding to what was said that in g++ you can turn on a warning to prevent you from doing this kind of mistake: -Wconversion flag.

-Wconversion

Warn for implicit conversions that may alter a value. This includes conversions between real and integer, like abs (x) when x is double; conversions between signed and unsigned, like unsigned ui = -1; and conversions to smaller types, like sqrtf (M_PI). Do not warn for explicit casts like abs ((int) x) and ui = (unsigned) -1, or if the value is not changed by the conversion like in abs (2.0). Warnings about conversions between signed and unsigned integers can be disabled by using -Wno-sign-conversion.

For C++, also warn for confusing overload resolution for user-defined conversions; and conversions that will never use a type conversion operator: conversions to void, the same type, a base class or a reference to them. Warnings about conversions between signed and unsigned integers are disabled by default in C++ unless -Wsign-conversion is explicitly enabled.

Other compilers may have similar flags.

user812786
  • 4,302
  • 5
  • 38
  • 50
j4x
  • 3,595
  • 3
  • 33
  • 64
  • For MSVC, enable 4365 "signed/unsigned mismatch" to enable checking for this, it's been helpful for my code. – moltenform Oct 02 '16 at 05:39
0

By the time of the original C standard, the conversion was already allowed by many (all?) compilers. Based on the C rationale, there appears to have been little (if any) discussion of whether such implicit conversions should be allowed. By the time C++ came along, such implicit conversions were sufficiently common that eliminating them would have rendered the language incompatible with a great deal of C code. It would probably have made C++ cleaner; it would certainly have made it much less used -- to the point that it would probably never have gotten beyond the "C with Classes" stage, and even that would just be a mostly-ignored footnote in the history of Bell labs.

The only real question along this line was between "value preserving" and "unsigned preserving" rules when promoting unsigned values "smaller" than int. The difference between the two arises when you have (for example) an unsigned short being added to an unsigned char.

Unsigned preserving rules say that you promote both to unsigned int. Value preserving rules say that you promote both values to int, if it can represent all values of the original type (e.g., the common case of 8-bit char, 16-bit short, and 32-bit int). On the other hand, if int and short are both 16 bits, so int cannot represent all values of unsigned short, then you promote the unsigned short to unsigned int (note that it's still considered a promotion, even though it only happens when it's really not a promotion -- i.e., the two types are the same size).

For better or worse, (and it's been argued both directions many times) the committee chose value preserving rather than unsigned preserving promotions. Note, however, that this deals with a conversion in the opposite direction: rather than from signed to unsigned, it's about whether you convert unsigned to signed.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
-1

Because the standard allows implicit conversion from signed to unsigned types.

Also (int)a + (unsigned)b results to unsigned - this is a c++ standard.

artyom.stv
  • 2,097
  • 1
  • 24
  • 42
  • 4
    "Why does C++ allow this?" "Because C++ allows this". What unhelpful rubbish. I'd downvote you if I hadn't hit my daily votecap. – Lightness Races in Orbit Mar 10 '11 at 17:21
  • @Tomalak Geret'kal: You don't agree with the standard? Or What? When you program on assembler do you ask: "Why is this called `mov` and not `muv`"? – artyom.stv Mar 10 '11 at 17:23
  • 1
    @Tomalak Geret'kal: There is NO good answer on such question. – artyom.stv Mar 10 '11 at 17:24
  • 4
    @artyom.stv: Of course I agree with the standard. The question is about _why_ the standard says that. – Lightness Races in Orbit Mar 10 '11 at 17:27
  • 2
    @artyom.stv: why is there no good answers to such questions? The standard wasn't written by God, there are reasons why it says what it says, even if the reason boils down to "because person X believed fact Y, which actually is false, and it's too late to change now". Admittedly so far nobody has offered the C motivation. – Steve Jessop Mar 10 '11 at 17:30
  • @Tomalak Geret'kal: There are lots of questions "to standard". But how can YOU answer on them? Did you develop the standard? Of course C++ is C compliant - that was the Stroustrup's principle. But how can you know the motivation of Bjarne when he was developing C standard? Is your answer more informative? – artyom.stv Mar 10 '11 at 17:31
  • @Steve Jessop: Did you develop C standard? I did not. And you? – artyom.stv Mar 10 '11 at 17:32
  • 4
    @artyom: Bjarne has written a *book* about the reasons behind decisions made in the design of C++. By reading it we can know his motivations, at least as far as we trust him to remember them. You may as well ask how I can know what the standard itself says without having developed it. I have a copy, that's how human communication works ;-) – Steve Jessop Mar 10 '11 at 17:32
  • Tomalak provided possible (and good) answers to the question, you restated the question. – Khaled Nassar Mar 10 '11 at 17:33
  • @Steve Jessop: +1. agree. But is the answer: "C compliant" useful? – artyom.stv Mar 10 '11 at 17:34
  • 2
    @artyom: depends why the questioner was asking. That answer certainly provokes the question, "well then why does C allow it?", and I think that's why user168715 self-described the comment as "trite". – Steve Jessop Mar 10 '11 at 17:36
  • I agree that my answer is useles (comparing to the citation from Bjarne's book). – artyom.stv Mar 10 '11 at 17:36
  • There are plenty of elements of the standard the rationale for which we can discuss. Suggesting that we can't discuss reasons behind language features without being Bjarne (I think you meant the wider language committee) is .. strange. I can answer "why does `bool` hold only two possible states?" without being Bjarne. – Lightness Races in Orbit Mar 11 '11 at 01:06