3

I wanted to understand C++ types along with widening and narrowing conversions in a little bit more details (C++03 specific).I am aware that you cannot put multiple questions on a single question thread however all these questions are related to the same topic. Now I have the C++ types and ranges msdn

Now consider the following example:

int a = 35000;
short b;
b=a;

Now in the above example I know a is 4 bytes and b is 2 bytes. I am aware that a widening conversion increases precision where as a narrowing conversion decreases precision. The above example I believe would be a narrowing cast (since there is loss of data) 4 bytes is going into two bytes. However I get confused in certain cases what conversion is taking place is it widening or is it narrowing ? Are we suppose to look at the number of bytes of types to determine if it will be a widening or a narrowing conversion or are we suppose to look at ranges? Also I read that for narrowing conversion explicit casting is required however in this case the compiler did not point out any error and implicitly did the conversion which was wrong. Any suggestions on why that happened ? I am using VS2010

MistyD
  • 16,373
  • 40
  • 138
  • 240
  • There is a formal definition of what a *narrowing conversion* is in the C++11 Standard, but it doesn't apply to VS2010, since it is only used to specify list-initialization (which is not supported in VS2010). – dyp Sep 22 '14 at 19:46
  • possible duplicate of [Why compiler allows narrowing conversions](http://stackoverflow.com/questions/12873919/why-compiler-allows-narrowing-conversions) – Dale Wilson Sep 22 '14 at 19:46
  • " I read that for narrowing conversion explicit casting is required " - throw that book out – M.M Sep 22 '14 at 22:19

2 Answers2

7

Narrowing doesn't necessarily depend solely on size. For example, a long long and a double, are both normally the same size (64 bits apiece). Nonetheless, conversion in either direction is a narrowing conversion, because information can be lost either way. The same can happen with a conversion between a signed integer type and an unsigned integer type of the same size--conversion in either direction can lose information (i.e., result in a value that doesn't match the input) so both are considered narrowing conversions.

If you work solely within the same...class of types (e.g., all signed integers or all floating point), then you can use the size of the item to figure out whether a conversion will involve narrowing (in theory there might be times/situations where this was false, but it's true for the types provided by most hardware and compilers).

Also note that C++ does add some exceptions for conversions when the source is a literal, and the source value can be put in the destination without losing information, even though some values of the source type could lead to information loss.

For example, if I do something like float a = 3.5;, the literal 3.5 has type double, but since it's a literal and it can be converted to float without losing information, it's allowed even in places where narrowing conversions are prohibited (e.g., braced initialization lists).

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

For integral types, the precision is always 1. Widening conversion increases the range, narrowing conversion decreases the range.

http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx

The range of a short is –32,768 to 32,767. your input, 3500 is bigger than that. What ends up happening is the number gets crammed into the smaller number of bytes, causing a wrap around error (b is negative). (The specifics of that have to do with complements of 2 and what not, but for your level it is suffice to say "you broke it, it don't work").

To avoid, compiler with -Wnarrowing or -Wall with gcc, or /Wall with the visual studio compiler (i don't actually know if /Wall will catch it though).

IdeaHat
  • 7,641
  • 1
  • 22
  • 53
  • Wikipedia: "dynamic change is the ratio between the largest and smallest possible values of a changeable quantity". It has nothing to do with whether or not that range can change, just the values. I've never heard the term "static range" before, though the point that these ranges don't change is a valid one. – IdeaHat Sep 22 '14 at 19:51
  • @dyp Allright, the dynamic range of a short is 1/(32,767-–32,768), (roughly 2^-16) the dynamic range of an int is 1/(2,147,483,647--–2,147,483,648) (roughly 2^-32). The *precision* of both (using the wording from OP) is 1. The precisions is only affected in narrowing if you are using floating point types. Should I move that to my answer? – IdeaHat Sep 22 '14 at 19:54
  • @dyp I changed it to just "range" to avoid confusion. – IdeaHat Sep 22 '14 at 19:56
  • Now of course the question remains whether `int` -> `unsigned int` is a narrowing conversion or not. Their ranges overlap, the sizes of their ranges are equal. According to the definition in the C++ Standard, those are still narrowing conversions (both `int` -> `unsigned int` and vice versa). – dyp Sep 22 '14 at 19:58
  • Out-of-range assignment causes implementation-defined behaviour (this might not be a "wrap-around") – M.M Sep 22 '14 at 22:21