Strange GCC short int conversion warning
When you do arithmetic computations, the operands are subject to "the usual arithmetic conversions" (a superset of the "integer promotions" quoted in Acme's answer—he beat me to this but I'll go ahead and post anyway :-) ). These widen short int
to plain int
, so:
a + b
computes the same result as:
((int) a) + ((int) b)
The return
statement must then narrow this int
to a short int
, and this is where gcc produces the warning.
warning: use of old-style cast in g++
reinterpret_cast
, static_cast
, dynamic_cast
and const_cast
are the c++ cast alternatives.
const_cast
to remove const/volatile from a const variable.dynamic_cast
to perform runtime validity checks when casting in between polymorphic typesstatic_cast
to perform e.g up/down-cast in a inheritance hierarchy, but with no runtime checks, or to explicitly perform conversions that could be implicit (e.g. float to int)reinterpret_cast
to convert in between unrelated types.
Brief syntax example:
char* a = (char*) b;
//would be
char* a = static_cast<char*>(b);
//to remove the warning
Explicit casting in C/C++
A. The initialization
double sign = -2 * (num % 2) + 1;
is perfectly well-defined. That's what I'd use; I don't think there's any need to complicate things with extra casts or anything.
C and C++ are well-defined and convenient in their implicit conversions between integer and floating-point types. Explicit conversions are usually not needed. In my experience there are only three things to worry about:
- Code like
double ratio = 1 / 3
doesn't do what you want; you need to force one of the operands to/
to be floating-point. (This has nothing to do with your question, but it's an extremely easy mistake to make.) - Overflow, if one type or the other can't represent the value. (Also not a problem for your example.)
- Overzealous compilers. Many compilers will "helpfully" warn you that you might lose precision when converting from
double
tofloat
, or from a floating-point type to an integer. So you may need explicit casts to silence those warnings.
B. Asking for the numeric value of a Boolean is perfectly well-defined (is guaranteed to give you a nice, clean, 1 or 0), so your second fragment should be fine also. (I know this is true for C, and per a comment below, it's true for C++ also.)
Is the behaviour of casting a negative double to unsigned int defined in the C standard? Different behaviour on ARM vs. x86
No
This conversion is undefined and therefore not portable.
C99/C11 6.3.1.4
When a finite value of real floating type is converted to an integer type other than _Bool,
the fractional part is discarded (i.e., the value is truncated toward zero). If the value of
the integral part cannot be represented by the integer type, the behavior is undefined.
According to C11 6.3.1.4 footnote 61:
The remaindering operation performed when a value of integer type is converted to unsigned type need not be performed when a value of real floating type is converted to unsigned type. Thus, the range of portable real floating values is (−1, Utype_MAX+1).
Warnings on sign conversion when assigning from the result of unsigned division
Clang is just being an extra bit clever: division of an unsigned integer by an unsigned integer larger or equal to 2 means the unsigned integer result will always fit in the signed integer counterpart (to that of the numerator type in the division expression). However, if you divide by an unsigned integer valued 1, the result is no longer guaranteed to fit in a signed integer counterpart, and Clang does emit a warning:
#include <cstdint>
int main() {
uint8_t a = 240; // '240 / 1' will not fit in int8_t
int8_t e = a / 2u; // No warning in clang
int8_t f = a / 1u; // warning: implicit conversion changes signedness: 'unsigned int' to 'int8_t' (aka 'signed char') [-Wsign-conversion]
}
One could also argue that Clang should be able to omit the warning for the similar special case of multiplication by 0; however Clang does not whereas GCC, instead, does:
// Clang warns, no warning in GCC.
int8_t g = a * 0u;
So peculiarly Clang is clever, in this context, w.r.t. division and GCC w.r.t. multiplication.
Finally, note that the gating for Clang to emit this warning during division seems to be only when dividing by 1, as you will not get the same -Wsign-conversion
if you divide by 0u
; arguably as it has been overridden by the more relevant (in such a context) -Wdivision-by-zero
warning:
int8_t h = a / 0u;
warning: division by zero is undefined [-Wdivision-by-zero]
How to fix C++ warning of implicit conversion?
This warning is triggered by the -Wsign-conversion
switch, detecting that you're taking a signed variable and converting it to an unsigned variable, in a way that may change the value.
It doesn't do it for positive literals, where the conversion obviously doesn't change the value, because that would be pointless and really annoying. You'll get it for a negative literal like -5
.
(Technically, this is the literal 5
with the unary negation operator applied, not a "negative literal"!).
For named variables it can't really predict what the value would be, so errs on the side of caution.
You should make your variable start
have type size_t
.
gcc scanf warning believes float is double
Which leads me to the question, why do gcc believe the second argument
of scanf to be a double, when it actually is a float?
Because float
is promoted to double
as specified in C Standard
6.5.2.2 Function calls
[#6] ... arguments
that have type float are promoted to double. These are
called the default argument promotions.[#7] ... The ellipsis notation in a function prototype
declarator causes argument type conversion to stop after the
last declared parameter. The default argument promotions
are performed on trailing arguments.
C++ : Implicit type conversion
See my comments.
This is well-defined. The intermediate expression for
z
will undergo widening intodouble
, soy * z
will be adouble
expression. An implicit narrowing conversion will then convert it tofloat
for storing inres2
. This same narrowing applies tores1
.
This is reflected by §5¶9 Expressions [expr] of the C++11 standard.
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows:
...
- Otherwise, if either operand is
double
, the other shall be converted todouble
.- Otherwise, if either operand is
float
, the other shall be converted tofloat
....
This, however, does not sure that the equality will hold.
That being said,
res1
need not necessarily be equivalent tores2
-- it is highly dependent on the precision offloat
anddouble
in the environment. The two literals could potentially not even be equal --4.23423451f
not need even be equivalent to4.23423451
. You can not be sure thatstatic_cast<double>(static_cast<float>(4.23423451))
will be equal to4.23423451
.
See §5.17¶3 Assignment and compound assignment operators [expr.ass].
If the left operand is not of class type, the expression is implicitly converted (Clause 4) to the cv-unqualified type of the left operand.
§4 Standard conversions [conv] states as follows:
Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:
...
- Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.
As elaborated in §4.6 Floating point promotion [conv.fpprom],
- A prvalue of type
float
can be converted to a prvalue of typedouble
. The value is unchanged.- This conversion is called floating point promotion.
... and §4.8 Floating point conversions [conv.double],
A prvalue of floating point type can be converted to a prvalue of another floating point type. If the source value can be exactly represented in the destination type, the result of the conversion is that exact representation. If the source value is between two adjacent destination values, the result of the conversion is an implementation-defined choice of either of those values. Otherwise, the behavior is undefined.
The conversions allowed as floating point promotions are excluded from the set of floating point conversions.
The problem here is that we have multiple cases where our conversion is not promotion, but rather narrowing to a potentially lower-precision type (double
to float
).
Essentially, any time you convert double
to float
, you may potentially lose precision.
Related Topics
Forward Declaration & Circular Dependency
Best Way to for C++ Types to Self Register in a List
Qmetaobject::Connectslotsbyname: No Matching Signal
Boost.Python: Wrap Functions to Release the Gil
Class' Keyword in Variable Definition in C++
Why Do I Need to Include Both the iOStream and Fstream Headers to Open a File
Const and Non Const Template Specialization
Using Std::Make_Unique with a Custom Deleter
Can You Start a Class Name with a Numeric Digit
Openal: How to Create Simple "Microphone Echo" Programm
Why Openmp Under Ubuntu 12.04 Is Slower Than Serial Version