I just learned C++ style casting and the 4 types of casts. I'm not sure if I'm abusing it though.

Examples:

typedef long (*stringFromString)(int, char*) __cdecl;

//TO:

typedef long static_cast<*stringFromString>((int, char*)) __cdecl;



SmartSetup((char*)World.c_str(), (char*)",f5", 765, 503,(char*)"");

//TO:

SmartSetup(static_cast<char*>(World.c_str()), static_cast<char*>(",f5"), 765, 503, static_cast<char*>(""));




memcpy(&INH, (void*)((DWORD)Buffer + IDH.e_lfanew), sizeof(INH));

TO:

memcpy(&INH, static_cast<void*>(static_cast<DWORD>(Buffer) + IDH.e_lfanew), sizeof(INH));



std::function<void()> func = *((std::function<void()>*)lpParameter);

TO:

std::function<void()> func = *(static_cast<std::function<void()>*>(lpParameter));

I'm not sure when I should use re-interpret cast or if I'm abusing this type of cast I'm currently using. Should I leave everything as C-Style cast? How does it affect typedefs when importing from a DLL? How can I cast: (void*) &Meh using C++?? I used a static cast to void*.

Recommended Answers

All 4 Replies

typedef long static_cast<stringFromString>((int, char)) __cdecl;

This is completely nonsensical. Casting is a form of coercion of objects to another type. The bytes of the object are interpreted as the new type. A typedef is not an object.

SmartSetup((char*)World.c_str(), (char*)",f5", 765, 503,(char*)"");

//TO:

SmartSetup(static_cast<char*>(World.c_str()), static_cast<char*>(",f5"), 765, 503, static_cast<char*>(""));

c_str() already returns a pointer to const char, so the only use for a cast when calling SmartSetup() would be to remove the constness of the pointer if SmartSetup() is defined as:

T SmartSetup(char* a, char* b, int c, int d, char* e);

But even then, string literals have special rules that allow such a conversion without incident. It's deprecated, but still legal. ;) Anyway, since the point of the cast is to remove constness, you'd be better off using const_cast:

SmartSetup(const_cast<char*>(World.c_str()), 
        const_cast<char*>(",f5"), 
        765, 
        503, 
        const_cast<char*>(""));
memcpy(&INH, (void*)((DWORD)Buffer + IDH.e_lfanew), sizeof(INH));

TO:

memcpy(&INH, static_cast<void*>(static_cast<DWORD>(Buffer) + IDH.e_lfanew), sizeof(INH));

This looks hairy regardless of the cast. If Buffer is already a pointer then there's no need for any cast because all pointers have an implicit conversion to void*. If Buffer isn't a pointer then you might be doing something exceedingly risky. I'm not sure why Buffer is being cast to DWORD here, and there's no context for me to figure it out. So I'll just assume that Buffer is a pointer and all casts may be safely removed:

memcpy(&INH, Buffer + IDH.e_lfanew, sizeof(INH));
std::function<void()> func = *((std::function<void()>*)lpParameter);

TO:

std::function<void()> func = *(static_cast<std::function<void()>*>(lpParameter));

This is another case of the cast being unnecessary. std::function knows what it's about and has an appropriate constructor for the target type. If lpParameter isn't a pointer to function that returns void and takes no parameters, that's a different matter. But in such a case I'd question why you're trying to mix function types that aren't compatible in the first place. ;)

So out of your four examples, only one of them potentially needed a cast at all. That's quite convenient for me since the key point when it comes to casting is to avoid it if at all possible, and that lesson falls out of your examples naturally. :D

Hmm I fixed what you said. The reason I had to cast the std::function was because lpParameter is a void* and I had to turn it into a function inorder to use it. Removing the cast there will not work. Also I have a couple more questions.

  1. What if I want to go from char* to BYTE*? I'd use reinterpret_cast right?

  2. From const char* to BYTE* I'd do: reinterpret_cast<BYTE*>(const_cast<char*>(InitialValue.c_str()))

But I'm skeptical about doing such things because I read that reinterpret casts are very bad. But static_cast doesn't do this sorta thing and neither does dynamic so I'm not sure whether to reinterpret_cast or use c-style casting.

Also some of my functions such as FormatMessage wrapper:

inline void ErrorMessage(DWORD Error, bool ExitProcess = false)
{
    char* lpMsgBuf = nullptr;
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<char*>(&lpMsgBuf), 0, 0);
    std::cout<<lpMsgBuf;
    if (ExitProcess) exit(Error);
}

//See this cast? reinterpret_cast<char*>(&lpMsgBuf)
//Why do I have to use reinterpret to cast from a pointer?

Are C-Style casts even that bad? I mean they look much neater in code and they are equivalent to whichever of the 4 casts works first. So how can that be a bad thing?

What if I want to go from char* to BYTE*? I'd use reinterpret_cast right?

Correct, assuming BYTE isn't defined as char.

From const char* to BYTE* I'd do: reinterpret_cast<BYTE*>(const_cast<char*>(InitialValue.c_str()))

That's terrifying. First, casting away the const for the result of c_str() is begging for trouble, especially if you or some function you call tries to modify it. Second, the lifetime of the string returned by c_str() is questionable. You'd be much better off making a copy first, if the result is to have any significant life span.

But static_cast doesn't do this sorta thing and neither does dynamic so I'm not sure whether to reinterpret_cast or use c-style casting.

You can think of C-style casts as a god mode cast, they're essentially unrestricted. The C++ casts are restricted to their specific uses. const_cast is an ideal example: it modifies const/volatile qualifiers and nothing else.

If you're using C++ casts, then the best approach would probably be to avoid C-style casts entirely.

//See this cast? reinterpret_cast<char*>(&lpMsgBuf)
//Why do I have to use reinterpret to cast from a pointer?

The documentation for FormatMessage() says that you need to cast to LPTSTR, not char*. This distinction is important because LPTSTR could be defined as char* or wchar_t* depending on your unicode settings.

In this case, the Windows API is evil. Based on the flags from the first argument, FormatMessage() will treat the fifth argument differently. In one case it's a simple caller provided buffer and in another case it's a pointer to a pointer that will be internally allocated new memory. Such a design is very poor indeed.

Are C-Style casts even that bad?

I don't think so. I very rarely use the C++ casts in favor of C-style casts. However, the C++ casts are much easier to search for in code.

What if I want to go from char* to BYTE*? I'd use reinterpret_cast right?

Yes and no at the same time. The reinterpret_cast is, generally, to be avoided because almost anything you do with it is "undefined behavior", except for this one case you pointed out. When casting pointers whose only common base is void* (i.e., the pointee types are completely unrelated), the expression reinterpret_cast<T*>(p) is required, by the standard, to be exactly equivalent to static_cast<T*>(static_cast<void*>(p)), which makes the reinterpret-cast just a shorter syntax for a double static-cast (cast up to a void-pointer and back down to a T-pointer). But, in almost all other cases, the C++ standard only requires that the reinterpret-cast be a reversible cast (and should only be used for that purpose), meaning that if you cast a A* pointer into a B* pointer and then cast it back to a A* pointer, then the A* pointer value should be the same. But, technically, the value of the intermediate B* pointer (the actual address it holds) is implementation-defined. In practice (not guaranteed by the standard, but often so in implementations), it will probably behave the same as one static-cast or as two static-cast (via a void-pointer, like in the case where the two types are completely unrelated), but there are cases where it might not (like cases where a static-cast would fail or be ambiguous, then, the output of the reinterpret-cast is really anybody's guess).

And, of course, when it comes to using reinterpret-cast for other objects (non-pointers), well, you should probably be using another technique to be sure you are getting the bits that you want (e.g., a union or variant type, or some other bitfield or byte-buffer technique). The only other common purpose for reinterpret_cast is for creating an "invalid value" (or pointer) like std::size_t invalid_index_value = reinterpret_cast<std::size_t>(-1);.

From const char* to BYTE* I'd do: reinterpret_cast<BYTE*>(const_cast<char*>(InitialValue.c_str()))

const_cast is probably the least useful casting operator in C++, because it only serves two purposes: violate interfaces, and create blatantly wrong code. Your line of code falls in the latter category (or both). The char-pointer that is obtained from the C++ string is not to be modified, and that's why there is a const on it. Don't cast away the constness on it because modifying it could make the C++ string object be corrupt. If you have a function that must take a BYTE* but doesn't actually modify the bytes that are pointed-to, then that function should be taking a const BYTE* pointer. If you cannot change that (i.e., you are using an external library, or a C library that doesn't support constness), then, sure, your code is OK, as long as you read the documentation of that function and make sure that it does not modify the bytes at all.

This last point is true for most "good practices" in C++. Generally, when you are getting close to a C interface (from an external library) many of the good practices guidelines of C++ (like avoiding reinterpret- or const-casts) go out the window, because you have to comply with the rules of C.

But I'm skeptical about doing such things because I read that reinterpret casts are very bad.

Very often, the term "very bad" just means that "you should know what you are doing, be careful, and use only in very specific situations".

But static_cast doesn't do this sorta thing and neither does dynamic

The static-cast certainly can work in these two situations (instead of the reinterpret-cast), but as I said, it is the same, only more verbose because you need two casts. The dynamic-cast has a completely different purpose. When it comes to casting between pointers (or references) of classes that are related by some inheritance hierarchy, then the only two options are static_cast or dynamic_cast, don't even think of using a reinterpret_cast for that purpose!

reinterpret_cast<char*>(&lpMsgBuf)

That's just the kind of crazy stuff you have to pull when you deal with the Windows API (and other extremely poorly designed APIs).

Are C-Style casts even that bad? I mean they look much neater in code and they are equivalent to whichever of the 4 casts works first. So how can that be a bad thing?

The problem with C-style casts is mostly what you said, it just picks whatever cast works. Which cast? You might write something like this:

class Foo { };

class Bar : private Foo { };

int main() {
  Bar b;
  Foo* pf1 = (Foo*)&b;  // what casting method is used here? Well..
  Foo* pf2 = static_cast<Foo*>(&b);  // ERROR: base-class Foo is inaccessible!
  Foo* pf3 = reinterpret_cast<Foo*>(&b);  // OK.. but what actually happened here?
};

The vast majority of the time in C++, you want to do static-casts. But, using the C-style syntax for that purpose can let erroneous code compile, as it falls back on the reinterpret-cast method as opposed to telling you about the error. When you use static-cast, in these types of situations, you'll try to compile, get an error, go "face-palm" and fix it, and that'll be the end of that. When you use a C-style cast, you'll compile it just fine, you'll run it, it might work perfectly fine, and months later you make some innocent-looking change to the code (which changes the binary layout) and you get stuck with the kind of bug that will make you want to throw your computer out the window (if not yourself too). That's the difference.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.