What is a difference between ((int) a) and (int(a))?
Is the second expression valid in pure "С" (not "C" under "C++")?
There's no difference between them in C++. However, C supports only the first cast operation.
See this example from tutorial:
double x = 10.3;
int y;
y = (int) x; // c-like cast notation
y = int (x); // functional notation
(type_name)identifier (or more specifically (type_name)cast_expression (6.5.4)) is a C-style cast. (int(a)) is syntactically invalid in C unless a is a type. Then it could be part of a cast to a function taking type a and returning int, which would be a syntactically valid but semantically invalid cast, so useless too. int(a); in C would be a declaration equivalent to int a;.
C++ does support the int(a) syntax for casts (the type name must be a single word; it doesn't work with e.g., unsigned long(a)) on the grounds that int (the type name) then becomes kind of like a type with a parametrized constructor (although even this is in C++ grouped together with C-style casts as a kind of a deprecated way of casting, and the more fine-grained/visible static_cast/reinterpret_cast/const_cast casts are preferred).
The C++ syntax then appears to be quite interesting because this works (C++):
typedef int type_name;
type_name (a); //a declaration
a=0;
printf("%d\n", type_name(a)); //type_name(a) is a cast expr here
Related
#include <iostream>
typedef enum my_time {
day,
night
} my_time;
int main(){
// my_time t1 = 1; <-- will not compile
int t2 = night;
return 0;
}
How is it expected that I can assign an enum value to an int but not the other way in C++?
Of course this is all doable in C.
Implicit conversions, or conversions in general, are not mutual. Just because a type A can be converted to a type B does not imply that B can be converted to A.
Old enums (unscoped enums) can be converted to integer but the other way is not possible (implicitly). Thats just how it is defined. See here for details: https://en.cppreference.com/w/cpp/language/enum
Consider that roughly speaking enums are just named constants and for a function
void foo(my_time x);
It is most likely an error to pass an arbitrary int. However, a
void bar(int x);
can use an enum for special values of x while others are still allowed:
enum bar_parameter { NONE, ONE, MORE, EVEN_MORE, SOME_OTHER_NAME };
bar(NONE);
bar(SOME_OTHER_NAME);
bar(42);
This has been "fixed" in C++11 with scoped enums that don't implicitly convert either way.
You could cast to int. This expression makes an explicit conversion of the specified data type (int) and the given value (night).
int t2 = static_cast<int>(night)
Of course this is all doable in C
That doesn't mean that the minds behind C++ automatically consider it a desired behavior. Nor should they have such an attitude. C++ follows its own philosophy with regard to types. This is not the only aspect where a conscious decision was made to be more strongly typed than C. This valid C snippet is invalid in C++
void *vptr = NULL;
int *iptr = vptr; // No implicit conversion from void* to T* in C++
How is it expected that I can assign an enum value to an int but not the other way in C++?
It's the behavior because one side of the conversion is less error prone. Allowing an enumerator to become an integer isn't likely to break any assumptions the programmer has about an integer value.
An enumeration is a new type. Some of the enmueration's values are named. And for most cases of using an enumeration, we really do want to restrict ourselves to those named constants only.
Even if an enumeration can hold the integer value, it doesn't mean that value is one of the named constants. And that can easily violate the assumptions code has about its input.
// Precondition: e is one of the name values of Enum, under pain of UB
void frombulate_the_cpu(Enum e);
This function documents its precondition. A violation of the precondition can cause dire problems, that's what UB usually is. If an implicit conversion was possible everywhere in the program, it'd be that more likely that we violate the precondition unintentionally.
C++ is geared to catch problems at compile time whenever it can. And this is deemed problematic.
If a programmer needs to convert an integer an enumeration, they can still do it with a cast. Casts stand out in code-bases. They require a conscious decision to override a compiler's checks. And it's a good thing, because when something potentially unsafe is done, it should be with full awareness.
Cast the int when assigning . . .
my_time t1 = (my_time)1;
Let's say, in C++11, I do
auto a = 4;
What will a be? An int (as I often read), an unsigned int, a short, a long, a size_t, a char? Is the behaviour of auto always defined, will it always be the exact same type (with the exact same bit length!) on each compiler and each architecture?
Another example:
class A{};
class B:A{};
auto x = new B();
Will x be of type *B or of type *A? Always the same on each compiler and platform? Both are perfectly legit, how does the compiler know which one I intend?
Is there an exact list of the auto behaviour?
What will a be?
int, since that's the type of 4.
Will x be of type *B or of type *A?
B*, since that's the type of new B().
Is there an exact list of the auto behaviour?
Usually, it's the type of the initialiser; unless that's a reference type, in which case it's the underlying object type. There are a few other wrinkles for unusual types like arrays, as mentioned in the comments.
will it always be the exact same type (with the exact same bit length!) on each compiler and each architecture?
In most cases, the initialiser has a well-defined type, and that determines the type deduced by auto.
If the initialiser is an integer literal, then the type might depend on the platform; for example, 1000000 might be int on a 32-bit platform, but long on a 16-bit platform.
Every expression in C++ has a type. auto can only be used
when there is an initialization expression. The type will be
the type of that expression. The expression 4, for example,
has type int, always, and the type of new B() is B*,
always.
Of course, the fact that the type is clear to the compiler
doesn't mean that it is clear to the reader. Abuse of auto is
a good way of rendering a program unreadable, and also of making
it fragile, since the compiler cannot check whether they type of
the initialization expression is compatible with the desired
type.
In the first case, a will be a int, see bellow:
auto a = 4 ; // int
auto b = 4U ; // unsigned int
auto c = 4L ; // long int
auto d = 4LLU ; // unsigned long long int, maybe it's ULL i don't remember...
auto x = 4.0 ; // double
auto y = 4.0f ; // float
In fact, there is a way to write any 'type of' int in C.
For new B(), well the compiler will take the only answer, which is B *.
auto match the type of the right value the variable is assigned to, without trying to infer anything, it's not its job!
You should not see the auto keyword as a magic stuff, but just something than may help you in case you don't want to have big declaration type.
The compiler doesn't know what you intend, and it doesn't care. The type of a or x is the type of the expression on the right hand side. Since the type of 4 is int, and the type of new B() is B*, it's the same as if you wrote int a = 4; B* x = new B();
The C++ standards mentions that reinterpret_cast is implementation defined, and doesn't give any guarantees except that casting back (using reinterpret_cast) to original type will result in original value passed to first.
C-style casting of at least some types behaves much the same way - casting back and forth results with the same value - Currently I am working with enumerations and ints, but there are some other examples as well.
While C++ standard gives those definitions for both cast-styles, does it also give the same guarantee for mixed casts? If library X returns from function int Y() some enum value, can use any of above casts, without worrying what cast was used to convert initial enum to int in Y's body? I don't have X's source code, so I cannot check (and it can change with next version anyway), and things like that are hardly mentioned in documentation.
I know that under most implementations in such cases both casts behave the same; my question is: what does C++ standard say about such cases - if anything at all.
C++ defines the semantic of the C cast syntax in terms of static_cast, const_cast and reinterpret_cast. So you get the same guaranteed for the same operation whatever syntax you use to achieve it.
reinterpret_cast can only be used for specific conversions:
Pointer to (sufficiently large) integer, and the reverse
Function pointer to function pointer
Object pointer to object pointer
Pointer-to-member to pointer-to-member
lvalue expression to reference
plus (conditionally) function pointer to object pointer and the reverse. In most cases, the converted value is unspecified, but there is a guarantee that a conversion followed by its reverse will yield the original value.
In particular, you can't use reinterpret_cast to convert between integer an enumeration types; the conversion must be done using static_cast (or implicitly, when converting an unscoped enumeration to an integer type), which is well defined for sufficiently large integer types. The only possible problem is if the library did something completely insane such as return reinterpret_cast<int&>(some_enum);
A C-style cast will perform either a static_cast or a reinterpret_cast, followed by a const_cast, as necessary; so any conversion that's well-defined by static_cast is also well-defined by a C-style cast.
No, reinterpret_cast is not equivalent to a C style cast. C style casts allow casting away const-volatile (so it includes the functionality of const_cast) not allowed in reinterpret_cast. If static_cast is allowed between the source and destination types, it will perform a static_cast which has different semantics than reinterpret_cast. It the conversion is not allowed, it will fallback to reinterpret_cast. Finally there is a corner case where the C cast cannot be represented in terms of any of the other casts: it ignores access specifiers.
Some examples that illustrate differences:
class b0 { int a; };
class b1 { int b; };
class b2 { int c; };
class d : public b0, public b1, b2 {};
int main() {
d x;
assert( static_cast<b1*>(&x) == (b1*)&x );
assert( reinterpret_cast<b1*>(&x) != (b1*)&x ); // Different value
assert( reinterpret_cast<b2*>(&x) != (b2*)&x ); // Different value,
// cannot be done with static_cast
const d *p = &x;
// reinterpret_cast<b0*>(p); // Error cannot cast const away
(b0*)p; // C style can
}
What is Type Conversion and what is Type Casting?
When should I use each of them?
Detail: Sorry if this is an obvious question; I'm new to C++, coming from a ruby background and being used to to_s and to_i and the like.
Conversion is when a value is, um, converted to a different type. The result is a value of the target type, and there are rules for what output value results from what input (of the source type).
For example:
int i = 3;
unsigned int j;
j = i; // the value of "i" is converted to "unsigned int".
The result is the unsigned int value that is equal to i modulo UINT_MAX+1, and this rule is part of the language. So, in this case the value (in English) is still "3", but it's an unsigned int value of 3, which is subtly different from a signed int value of 3.
Note that conversion happened automatically, we just used a signed int value in a position where an unsigned int value is required, and the language defines what that means without us actually saying that we're converting. That's called an "implicit conversion".
"Casting" is an explicit conversion.
For example:
unsigned int k = (unsigned int)i;
long l = long(i);
unsigned int m = static_cast<unsigned int>(i);
are all casts. Specifically, according to 5.4/2 of the standard, k uses a cast-expression, and according to 5.2.3/1, l uses an equivalent thing (except that I've used a different type). m uses a "type conversion operator" (static_cast), but other parts of the standard refer to those as "casts" too.
User-defined types can define "conversion functions" which provide specific rules for converting your type to another type, and single-arg constructors are used in conversions too:
struct Foo {
int a;
Foo(int b) : a(b) {} // single-arg constructor
Foo(int b, int c) : a(b+c) {} // two-arg constructor
operator float () { return float(a); } // conversion function
};
Foo f(3,4); // two-arg constructor
f = static_cast<Foo>(4); // conversion: single-arg constructor is called
float g = f; // conversion: conversion function is called
Classic casting (something like (Bar)foo in C, used in C++ with reinterpret_cast<>) is when the actual memory contents of a variable are assumed to be a variable of a different type. Type conversion (ie. Boost's lexical_cast<> or other user-defined functions which convert types) is when some logic is performed to actually convert a variable from one type to another, like integer to a string, where some code runs to logically form a string out of a given integer.
There is also static and dynamic casting, which are used in inheritance, for instance, to force usage of a parent's member functions on a child's type (dynamic_cast<>), or vice-versa (static_cast<>). Static casting also allows you to perform the typical "implicit" type conversion that occurs when you do something like:
float f = 3.14;
int i = f; //float converted to int by dropping the fraction
which can be rewritten as:
float f = 3.14;
int i = static_cast<int>(f); //same thing
In C++, any expression has a type. when you use an expression of one type (say type S) in a context where a value of another type is required (say type D), the compiler tries to convert the expression from type S to type D. If such an implicit conversion doesn't exist, this results in an error. The word type cast is not standard but is the same as conversion.
E.G.
void f(int x){}
char c;
f(c); //c is converted from char to int.
The conversions are ranked and you can google for promotions vs. conversions for more details.
There are 5 explicit cast operators in C++ static_cast, const_cast, reinterpret_cast and dynamic_cast, and also the C-style cast
Type conversion is when you actually convert a type in another type, for example a string into an integer and vice-versa, a type casting is when the actual content of the memory isn't changed, but the compiler interpret it in a different way.
Type casting indicates you are treating a block of memory differently.
int i = 10;
int* ip = &i;
char* cp = reinterpret_cast<char*>(ip);
if ( *cp == 10 ) // Here, you are treating memory that was declared
{ // as int to be char.
}
Type conversion indicates that you are converting a value from one type to another.
char c = 'A';
int i = c; // This coverts a char to an int.
// Memory used for c is independent of memory
// used for i.
I understand that reinterpret_cast is dangerous, I'm just doing this to test it. I have the following code:
int x = 0;
double y = reinterpret_cast<double>(x);
When I try to compile the program, it gives me an error saying
invalid cast from type 'float' to type 'double
What's going on? I thought reinterpret_cast was the rogue cast that you could use to convert apples to submarines, why won't this simple cast compile?
In C++ reinterpret_cast can only perform a specific set of conversions, explicitly listed in the language specification. In short, reinterpret_cast can only perform pointer-to-pointer conversions and reference-to-reference conversions (plus pointer-to-integer and integer-to-pointer conversions). This is consistent with the intent expressed in the very name of the cast: it is intended to be used for pointer/reference reinterpretation.
What you are trying to do is not reinterpretation. If you want to reinterpret an int as a double you'd have to convert it to a reference type
double y = reinterpret_cast<double&>(x);
although the equivalent pointer-based reinterpretation is probably more explicit
double y = *reinterpret_cast<double*>(&x); // same as above
Note though, that while reinterpret_cast can convert the reference/pointer types, the actual attempt to read the data through the resultant reference/pointer produces undefined behavior.
And in any case this, of course, can't make much sense on a platform with int and double of different size (since in case of larger double you will read beyond the memory occupied by x).
So, in the end it all boils down to what you were trying to achieve. Memory reinterpretation? See above. Some kind of more meaningful int to double conversion? If so, reinterpret_cast won't help you here.
Perhaps a better way of thinking of reinterpret_cast is the rouge operator that can "convert" pointers to apples as pointers to submarines.
By assigning y to the value returned by the cast you're not really casting the value x, you're converting it. That is, y doesn't point to x and pretend that it points to a float. Conversion constructs a new value of type float and assigns it the value from x. There are several ways to do this conversion in C++, among them:
int main()
{
int x = 42;
float f = static_cast<float>(x);
float f2 = (float)x;
float f3 = float(x);
float f4 = x;
return 0;
}
The only real difference being the last one (an implicit conversion) will generate a compiler diagnostic on higher warning levels. But they all do functionally the same thing -- and in many case actually the same thing, as in the same machine code.
Now if you really do want to pretend that x is a float, then you really do want to cast x, by doing this:
#include <iostream>
using namespace std;
int main()
{
int x = 42;
float* pf = reinterpret_cast<float*>(&x);
(*pf)++;
cout << *pf;
return 0;
}
You can see how dangerous this is. In fact, the output when I run this on my machine is 1, which is decidedly not 42+1.
If you are trying to convert the bits of your int to a the representation of a double, you need to cast the address not the value. You must also make sure the sizes match:
uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
reinterpret_cast is not a general cast. According to the C++03 spec section 5.2.10.1:
Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.
And there is nothing listed that describes converting between integral and floating point types (or between integral types, even this is illegal reinterpret_cast<long>(int(3));)
The compiler rejects what you wrote as nonsense because int and double may be objects with different sizes. You could achieve the same effect this way, although it is certainly dangerous:
int x = 0;
double y = *reinterpret_cast<double*>(&x);
This is potentially dangerous because if x and y are diffrent sizes (let's say int is four bytes and double is eight bytes) then when you dereference the eight bytes of memory at &x to fill in y you will access four bytes of x and four bytes of ... whatever comes next in memory (possibly the start of y, or garbage, or something else entirely.)
If you want to convert a integer to a double, use a static_cast and it will perform conversion.
If you want to access the bit-pattern of x, cast to some convenient pointer type (say, byte*) and access up to sizeof(int) / sizeof(byte):
byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
// do something with p[i]
}
Reinterpret cast allows you to reinterpret a block of memory as a different type. This has to be performed on pointers or references:
int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f ); // !!
The other thing is that it is in fact a quite dangerous cast, not only due to strange values coming out as results, or the assert above not failing, but because if the types are of different sizes, and you reinterpret from 'source' to 'destination' types, any operation on the reinterpreted reference/pointer will access sizeof(destination) bytes. If sizeof(destination)>sizeof(source) then that will step beyond the actual variable memory, potentially killing your application or overwritting other variables other than the source or destination:
struct test {
int x;
int y;
};
test t = { 10, 20 };
double & d = reinterpret_cast<double&>( t.x );
d = 1.0/3.0;
assert( t.x != 10 ); // most probably at least.
assert( t.y != 20 );
The reinterpret approach led me down a strange path with inconsistent results. In the end I found it much better to memcpy like this!
double source = 0.0;
uint64_t dest;
memcpy(&dest, &source, sizeof dest);
reinterpret_cast is best used for pointers. So a pointer to one object can be turned into a "submarine".
From msdn:
The reinterpret_cast operator can be
used for conversions such as char* to
int*, or One_class* to
Unrelated_class*, which are inherently
unsafe.
The result of a reinterpret_cast
cannot safely be used for anything
other than being cast back to its
original type. Other uses are, at
best, nonportable.
That's interesting. Maybe it's doing an implicit conversion from int to float before it attempts the cast to double. int and float types tend to be the same size in bytes (depending on your system of course).
Casting an int to a double doesn't require a cast. The compiler will perform the assignment implicitly.
The reinterpret_cast is used with pointers and references, e.g., casting an int * to a double *.
Use a union. It is the least error-prone way to memory map between an integer and a floating point type. Reinterpreting a pointer will cause aliasing warnings.
#include <stdio.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
union { uint32_t i; float f; } v; // avoid aliasing rules trouble
v.i = 42;
printf("int 42 is float %f\n", v.f);
v.f = 42.0;
printf("float 42 is int 0x%08x\n", v.i);
}