Is It Ok to Use C-Style Cast for Built-In Types

Is it OK to use C-style cast for built-in types?

I would not, for the following reasons:

  • Casts are ugly and should be ugly and stand out in your code, and be findable using grep and similar tools.
  • "Always use C++ casts" is a simple rule that is much more likely to be remembered and followed than, "Use C++ casts on user-defined types, but it's OK to use C-style casts on built-in types."
  • C++ style casts provide more information to other developers about why the cast is necessary.
  • C-style casts may let you do conversions you didn't intend -- if you have an interface that takes in (int*) and you were using c-style casts to pass it a const int*, and the interface changes to take in a long*, your code using c-style casts will continue to work, even if it's not what you wanted.

In C++, can we use { } for C-Style casting?

Is int{c} another way of casting data types?

Yes. T{value} creates a temporary of type T that is direct-list-initialized with the specified braced-init-list. This cast does have an advantage over T(value) in that T{value} can be used to create a temporary array. That would be done like

int main() {
using int_array = int[5];
for( auto e : int_array{1,2,3,4,5})
std::cout << e;
}

It also comes with the caveat that a narrowing conversion is a error

int main() {
int(10000000000ll); // warning only, still compiles
int{10000000000ll}; // hard error mandated by the standard
}

After some research on the net, I know that C++ casting is different and it have the compiler check the casting possibility at the compile time, but what are the differences between 1 and 2?

The big difference between T(value) and (T)value is that in T(value), T must be a single word. For example

int main() {
unsigned int(10000000); // error
(unsigned int)10000000; // compiles
}

Q3: Are there any other ways to explicitly convert/cast?

Well in C++ they want you to use the C++ casts which are static_cast, reinterpret_cast, dynamic_cast, and const_cast. Those are preferred over c style cast as a c style cast will do all of those where the C++ versions have certain limitations and come with certain guarantees.

What is the difference between static_cast and C style casting?

C++ style casts are checked by the compiler. C style casts aren't and can fail at runtime.

Also, c++ style casts can be searched for easily, whereas it's really hard to search for c style casts.

Another big benefit is that the 4 different C++ style casts express the intent of the programmer more clearly.

When writing C++ I'd pretty much always use the C++ ones over the the C style.

C++ cast syntax styles

It's best practice never to use C-style casts for three main reasons:

  • as already mentioned, no checking is performed here. The programmer simply cannot know which of the various casts is used which weakens strong typing
  • the new casts are intentionally visually striking. Since casts often reveal a weakness in the code, it's argued that making casts visible in the code is a good thing.
  • this is especially true if searching for casts with an automated tool. Finding C-style casts reliably is nearly impossible.

As palm3D noted:

I find C++-style cast syntax too verbose.

This is intentional, for the reasons given above.

The constructor syntax (official name: function-style cast) is semantically the same as the C-style cast and should be avoided as well (except for variable initializations on declaration), for the same reasons. It is debatable whether this should be true even for types that define custom constructors but in Effective C++, Meyers argues that even in those cases you should refrain from using them. To illustrate:

void f(auto_ptr<int> x);

f(static_cast<auto_ptr<int> >(new int(5))); // GOOD
f(auto_ptr<int>(new int(5)); // BAD

The static_cast here will actually call the auto_ptr constructor.

Difference between static casting styles in C++ for primitive values

In this case, they are equivalent. You should prefer the C++-style casts (static_cast, reinterpret_cast, dynamic_cast and const_cast) for all types, no matter if primitive or not, because you want to state your exact intention. The C-style cast is mightier than the others (taken individually) and should be avoided exactly for that reason.

If you apply a static_cast where it is not allowed, the compiler will complain. If you apply a C-style cast in the same situation, you may, for example, silently get a reinterpret_cast with undefined run-time behaviour instead of a compiler error.

What exactly is or was the purpose of C++ function-style casts?

Function style casts bring consistency to primitive and user defined types. This is very useful when defining templates. For example, take this very silly example:

template<typename T, typename U>
T silly_cast(U const &u) {
return T(u);
}

My silly_cast function will work for primitive types, because it's a function-style cast. It will also work for user defined types, so long as class T has a single argument constructor that takes a U or U const &.

template<typename T, typename U>
T silly_cast(U const &u) {
return T(u);
}

class Foo {};
class Bar {
public:
Bar(Foo const&) {};
};

int main() {
long lg = 1L;
Foo f;
int v = silly_cast<int>(lg);
Bar b = silly_cast<Bar>(f);
}

When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast isn't necessary, but it's important to note that the T(something) syntax is equivalent to (T)something and should be avoided (more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual inheritance. It does not do checking, however, and it is undefined behavior to static_cast down a hierarchy to a type that isn't actually the type of the object.


const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly const value is only undefined if the original variable is const; if you use it to take the const off a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object, such as to call a member function overload.

const_cast also works similarly on volatile, though that's less common.


dynamic_cast is exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can't, it will return nullptr in the case of a pointer, or throw std::bad_cast in the case of a reference.

dynamic_cast has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual inheritance. It also can only go through public inheritance - it will always fail to travel through protected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.


reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.


C-style cast and function-style cast are casts using (type)object or type(object), respectively, and are functionally equivalent. They are defined as the first of the following which succeeds:

  • const_cast
  • static_cast (though ignoring access restrictions)
  • static_cast (see above), then const_cast
  • reinterpret_cast
  • reinterpret_cast, then const_cast

It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed or reinterpret_cast will fail. Even then, consider the longer, more explicit option.

C-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.



Related Topics



Leave a reply



Submit