After reading here a lot of answers about C-style casting in C++ I still have one little question. Can I use C-style casting for built-in types like long x=(long)y;
If you are casting from a numeric type, to another numeric type, then I think C-style casts are preferable to *_cast
. Each of the *_cast
operators has a specific reason not to use it on numeric types:
reinterpret_cast
, when applied to numeric types, does a normal numeric conversion rather than reinterpreting the bits, i.e. writing reinterpret_cast<uint64_t>(3.14159)
does not produce the integer with the same bit representation as that floating-point constant. This is contrary to intuition.const_cast
is never necessary on a numeric value, and if applied to a numeric variable (as opposed to a pointer or reference to a number), suggests that the type of that variable is incorrect.dynamic_cast
just plain doesn't make sense on numbers because numbers never have dynamic type.static_cast
is normally used on class types. Therefore it looks strange to apply static_cast
to a number; your readers will scratch their heads and wonder if there's something they don't know about static_cast
that makes it different from the C-style cast when applied to a number. (In fact, they are identical, but I had to read the relevant C++ spec section a couple times to be sure they were identical, and I still have the "something weird must be going on here" reaction.)and there is an additional stylistic reason to avoid them:
If you need to cast among numeric types, you are likely to need to do several of them in a cluster; because of that, the concision of C-style casts is important. For instance, the program I'm writing right now has a whole bunch of this sort of thing:
uint32_t n = ((uint32_t(buf[0]) << 24) |
(uint32_t(buf[1]) << 16) |
(uint32_t(buf[2]) << 8) |
(uint32_t(buf[3]) ));
Using static_cast
here would obscure the arithmetic, which is the important thing. (Note: those casts are unnecessary only if sizeof(uint32_t) <= sizeof(unsigned int)
, which is a safe assumption nowadays but I still prefer the explicitness.) (Yes, I probably ought to factor out this operation into a be32_to_cpu
inline helper, but I'd still code it the same way.)
The one case where I prefer legacy C cast is casting byte buffers to different signedness. Many APIs have different conventions, and there is no "right answer" really, and the cast is not dangerous in the context it is done, where code needs to be only as platform-agnostic as the combination of libraries being used.
A concrete example for what I mean, I think this is just fine:
unsigned char foo[16];
lib1_load_foo(key);
lib2_use_foo((char*)key);
But for anything else, if cast is needed, it is going to have potential side-effects, which should stand out, and using C++ style (arguably ugly) cast is the right choice. And if cast is not needed, then don't use cast.
In my opinion C-Style casting of built in types when using standard library functions and STL is ok, and results in easier to read code.
In the company I work in we compile with maximum (level 4) warnings, so we get warnings about every little type cast etc... So I use c-style casts in these because they're small, not so verbose and make sense.
for (int i = 0; i < (int)myvec.size(); i++)
{
// do something int-related with i
}
float val = (float)atof(input_string);
etc....
But if its on (eg library) code that may change, then static_cast<>() is better because you can ensure the compiler will error out if types change and the cast no longer makes sense. Also, its impossible to search for casts within code if you only use c-style. "static_cast<mytype>(
" is pretty easy to search for. :)
I think it may be OK given the context. Example:
/* Convert -1..1 to -32768..32767 */
short float_to_short(float f)
{
return (short)(max(-32768.f, min(32767.f, f * 32767.f)));
}
I can think of one legitimate use for a C-style cast:
// cast away return value to shut up pedantic compiler warnings
(void)printf("foo\n");
I would not, for the following reasons: