difference between widening and narrowing in c++? - c++

What is the difference between widening and narrowing in c++ ?
What is meant by casting and what are the types of casting ?

This is a general casting thing, not C++ specific.
A "widening" cast is a cast from one type to another, where the "destination" type has a larger range or precision than the "source" (e.g. int to long, float to double). A "narrowing" cast is the exact opposite (long to int). A narrowing cast introduces the possibility of overflow.
Widening casts between built-in primitives are implicit, meaning you do not have to specify the new type with the cast operator, unless you want the type to be treated as the wider type during a calculation. By default, types are cast to the widest actual type used on the variable's side of a binary expression or assignment, not counting any types on the other side).
Narrowing casts, on the other hand, must be explicitly cast, and overflow exceptions must be handled unless the code is marked as not being checked for overflow (the keyword in C# is unchecked; I do not know if it's unique to that language)

widening conversion is when you go from a integer to a double, you are increasing the precision of the cast.
narrowing conversion is the inverse of that, when you go from double to integer. You are losing precision
There are two types of casting , implicit and explicit casting. The page below will be helpful. Also the entire website is pretty much the goto for c/c++ needs.
Tutorial on casting and conversion

Take home exam? :-)
Let's take casting first. Every object in C or C++ has a type, which is nothing more than the name give to two kinds of information: how much memory the thing takes up, and what operations you can do on it.
So
int i;
just means that i refers to some location in memory, usually 32 bits wide, on which you can do +,-,*,/,%,++,-- and some others.
Ci isn't really picky about it, though:
int * ip;
defines another type, called pointer to integer which represents an address in memory. It has an additional opertion, prefix-*. On many machines, that also happens to be 32 bits wide.
A cast, or typecast tell the compiler to treat memory identified as one type as if it were another type. Typecasts are written as (typename).
So
(int*) i;
means "treat i as if it were a pointer, and
(int) ip;
means treat the pointer ip as just an integer number.
Now, in this context, widening and narrowing mean casting from one type to another that has more or fewer bits respectively.

Related

Does going through uintptr_t bring any safety when casting a pointer type to uint64_t?

Note that this is purely an academic question, from a language lawyer perspective. It's about the theoretically safest way to accomplish the conversion.
Suppose I have a void* and I need to convert it to a 64-bit integer. The reason is that this pointer holds the address of a faulting instruction; I wish to report this to my backend to be logged, and I use a fixed-size protocol - so I have precisely 64 bits to use for the address.
The cast will of course be implementation defined. I know my platform (64-bit Windows) allows this conversion, so in practice it's fine to just reinterpret_cast<uint64_t>(address).
But I'm wondering: from a theoretical standpoint, is it any safer to first convert to uintptr_t? That is: static_cast<uint64_t>(reinterpret_cast<uintptr_t>(address)). https://en.cppreference.com/w/cpp/language/reinterpret_cast says (emphasis mine):
Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions (except when converting between integers and pointers or on obscure architectures where pointer representation depends on its type).
So, in theory, pointer representation is not defined to be anything in particular; going from pointer to uintptr_t might theoretically perform a conversion of some kind to make the pointer representable as an integer. After that, I forcibly extract the lower 64 bits. Whereas just directly casting to uint64_t would not trigger the conversion mentioned above, and so I'd get a different result.
Is my interpretation correct, or is there no difference whatsoever between the two casts in theory as well?
FWIW, on a 32-bit system, apparently the widening conversion to unsigned 64-bit could sign-extend, as in this case. But on 64-bit I shouldn't have that issue.
You’re parsing that (shockingly informal, for cppreference) paragraph too closely. The thing it’s trying to get at is simply that other casts potentially involve conversion operations (float/int stuff, sign extension, pointer adjustment), whereas reinterpret_cast has the flavor of direct reuse of the bits.
If you reinterpret a pointer as an integer and the integer type is not large enough, you get a compile-time error. If it is large enough, you’re fine. There’s nothing magical about uintptr_t other than the guarantee that (if it exists) it’s large enough, and if you then re-cast to a smaller type you lose that anyway. Either 64 bits is enough, in which case you get the same guarantees with either type, or it’s not, and you’re screwed no matter what you do. And if your implementation is willing to do something weird inside reinterpret_cast, which might give different results than (say) bit_cast, neither method will guarantee nor prevent that.
That’s not to say the two are guaranteed identical, of course. Consider a DS9k-ish architecture with 32-bit pointers, where reinterpret_cast of a pointer to a uint64_t resulted in the pointer bits being duplicated in the low and high words. There you’d get both copies if you went directly to a uint64_t, and zeros in the top half if you went through a 32-bit uintptr_t. In that case, which one was “right” would be a matter of personal opinion.

Is promotion and widening the same thing?

Is there's a difference between promotion and widening, I've heard that widening only describes integral promotion.
Widening "typically" refers to integral/floating point types (as in a char going to a long or float to double), but it can also refer to character widening (as in going from a char type to a wchar_t type).
Widening conversions are also known as "promotions" and narrowing conversions are known as "coercion".
The notion of "promotion" and "coercion" can also be used in the OO since as well (polymorphism); as in promotion of a base class to a derived type, or coercion of derived type to base. In this since it's still a "widening" and "narrowing" as the address space used for the base is "less" than the derived type (hence you are widening/promoting your types when "up-casting", or narrowing/coercing your types when "down-casting").
So to answer directly: Is there's a difference between promotion and widening .. no not really (unless you are feeling pedantic), though I probably wouldn't say "widen that class type" over "promote that class type" if I was talking about non-integrals (just to avoid any possible initial confusion).
It really depends on context, because the term "widening" is an informal term, and the meaning varies a bit depending on who is telling the story. I'll describe some common interpretations (but not the only ones).
Before doing that, it is necessary to describe what promotions are.
The C++ standard describes integral promotions (between integral types) and floating point promotions (between floating point types). Conversion between an integral type and a floating point type is not described as a promotion.
The common features are that promotions are generally value preserving (except from signed to unsigned integral types, which uses modulo arithmetic) but need not involve increasing the size of a variable (or range of values it can represent). For example, a short may be promoted to an int, but a short and an int may also be the same size (albeit that is implementation/compiler dependent).
The C++ standard doesn't use the term "widening" at all (except in some contexts in the library, unrelated to type conversions). A common informal meaning, in context of integral and floating point conversions, is a promotion that is BOTH value preserving AND to a larger type. The implementation is typically setting the additional bits in the result to zero (i.e. making the value wider without fiddling the bits that represent it). So signed char to short, short to long, unsigned char to unsigned short are widening conversions (assuming none of the types are equal size). Similarly, float to double is a widening conversion (the standard guarantees that the values a float can represent is a strict subset of the values that a double can represent). Conversion from int to double is not a widening (e.g. not necessarily value preserving, bits may be fiddled).
Widening is also sometimes used to describe a conversion of a pointer to derived class into a pointer to base class (or between similar references). The reverse is called "narrowing" and - in C++ - can only be forced with an explicit type conversion.

In C++, what happens when I use static_cast<char> on an integer value outside -128,127 range?

In a code compiled on i386 Linux using g++, I have used static_cast<char>() cast on a value that might exceed the valid range of -128,127 for a char. There were no errors or exceptions and so I used the code in production.
The problem is now I don't know how this code might behave when a value outside this range is thrown at it. There is no problem if data is modified or truncated, I only need to know how this modification behaves on this particular platform.
Also what would happen if C-style cast ((char)value) had been used? would it behave differently?
In your case this would be an explicit type conversion. Or to be more precise an integral conversions.
The standard says about this(4.7):
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and
bit-field width); otherwise, the value is implementation-defined.
So your problem is implementation-defined. On the other hand I have not yet seen a compiler that does not just truncate the larger value to the smaller one. And I have never seen any compiler that uses the rule mentioned above.
So it should be fairly safe to just cast your integer/short to the char.
I don't know the rules for an C cast by heart and I really try to avoid them because it is not easy to say which rule will kick in.
This is dealt with in §4.7 of the standard (integral conversions).
The answer depends on whether in the implementation in question char is signed or unsigned. If it is unsigned, then modulo arithmetic is applied. §4.7/2 of C++11 states: "If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2 n where n is the number of bits used to represent the unsigned type)." This means that if the input integer is not negative, the normal bit truncation you expect will arise. If is is negative, the same will apply if negative numbers are represented by 2's complement, otherwise the conversion will be bit altering.
If char is signed, §4.7/3 of C++11 applies: "If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined." So it is up to the documentation for the particular implementation you use. Having said that, on 2's complement systems (ie all those in normal use) I have not seen a case where anything other than normal bit truncation occurs for char types: apart from anything else, by virtue of §3.9.1/1 of the c++11 standard all character types (char, unsigned char and signed char) must have the same object representation and alignment.
The effect of a C style case, an explicit static_cast and an implicit narrowing conversion is the same.
Technically the language specs for unsigned types agree in inposing a plain base-2. And for unsigned plain base-2 its pretty obvious what extension and truncation do.
When going to unsigned, however, the specs are more "tolerant" allowing potentially different kind of processor to use different ways to represent signed numbers. And since a same number may have in different platform different representations is practically not possible to provide a description on what happen to it when adding or removing bits.
For this reason, language specification remain more vague by saying that "the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined"
In other words, compiler manufacturer are required to do the best as they can to keep the numeric value. But when this cannot be done, they are free to adapt to what is more efficient for them.

understanding widening and narrowing conversions C++

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

Implicit type conversions in expressions int to double

I've been trying to reduce implicit type conversions when I use named constants in my code. For example rather than using
const double foo = 5;
I would use
const double foo = 5.0;
so that a type conversion doesn't need to take place. However, in expressions where I do something like this...
const double halfFoo = foo / 2;
etc. Is that 2 evaluated as an integer and is it implicitly converted? Should I use a 2.0 instead?
The 2 is implicitly converted to a double because foo is a double. You do have to be careful because if foo was, say, an integer, integer division would be performed and then the result would be stored in halfFoo.
I think it is good practice to always use floating-point literals (e.g. 2.0 or 2. wherever you intend for them to be used as floating-point values. It's more consistent and can help you to find pernicious bugs that can crop up with this sort of thing.
This is known as Type Coercion. Wikipedia has a nice bit about it:
Implicit type conversion, also known as coercion, is an automatic type conversion by the compiler. Some languages allow, or even require, compilers to provide coercion.
In a mixed-type expression, data of one or more subtypes can be converted to a supertype as needed at runtime so that the program will run correctly.
...
This behavior should be used with caution, as unintended consequences can arise. Data can be lost when floating-point representations are converted to integral representations as the fractional components of the floating-point values will be truncated (rounded down). Conversely, converting from an integral representation to a floating-point one can also lose precision, since the floating-point type may be unable to represent the integer exactly (for example, float might be an IEEE 754 single precision type, which cannot represent the integer 16777217 exactly, while a 32-bit integer type can). This can lead to situations such as storing the same integer value into two variables of type integer and type real which return false if compared for equality.
In the case of C and C++, the value of an expression of integral types (i.e. longs, integers, shorts, chars) is the largest integral type in the expression. I'm not sure, but I imagine something similar happens (assuming floating point values are "larger" than integer types) with expressions involving floating point numbers.
Strictly speaking, what you are trying to achieve seems to be counterproductive.
Normally, one would strive to reduce the number of explicit type conversions in a C program and, generally, to reduce all and any type dependencies in the source code. Good C code should be as type-independent as possible. That generally means that it is a good idea to avoid any explicit syntactical elements that spell out specific types as often as possible. It is better to do
const double foo = 5; /* better */
than
const double foo = 5.0; /* worse */
because the latter is redundant. The implicit type conversion rules of C language will make sure that the former works correctly. The same can be said about comparisons. This
if (foo > 0)
is better than
if (foo > 0.0)
because, again, the former is more type-independent.
Implicit type conversion in this case is a very good thing, not a bad thing. It helps you to write generic type-independent code. Why are you trying to avoid them?
It is true that in some cases you have no other choice but to express the type explicitly (like use 2.0 instead of 2 and so on). But normally one would do it only when one really has to. Why someone would do it without a real need is beyond me.