views:

288

answers:

6

For example the following cast can be found littered throughout the MSDN documentation:

(LPTSTR)&lpMsgBuf

Should I bother converting that to:

static_cast<LPTSTR>(&lpMsgBuf);

Or should I just leave all the idiomatic C-esque Win32 portions as they are typically found in the docs, and save the more idiomatic C++ style/usage for the rest of my code?

+3  A: 

MSDN documentation vs C++ Standard.

I would choose the later. I think this is one of the rule discussed in effective C++ too. You should NOT mix two styles in one program.

J.W.
+11  A: 

New style casts were introduced for a reason: they're safer, more explanatory/self-commenting, easier to see, and easier to grep for.

So use them.

By more explanatory, we mean that you can't just cast to something, you have to say why you're casting (I'm casting in an inheritance hierarchy (dynamic_cast), my cast is implementation defined and possibly not portable (reinterpret_cast), I'm casting away constness (const_cast), etc.).

They're purposefully long and ugly so that the cast jumps out at the reader (and to discourage a programming style that employs too much casting).

They're safer because, e.g., you can't cast away constness without explicitly doing that.

tpdi
+3  A: 

You shouldn't need a cast at all -- from the looks of it, lpMsgBuf is a pointer to an array of characters (it's unclear from context if they are ANSI characters or wide characters), which you can pass directly to the various Win32 functions.

There's no need to take the address -- if lpMsgBuf is a static array (e.g. char lpMsgBuf[SIZE]), then taking its address is redundant and is equivalent to the address of its first element. If it's a pointer, then taking its address yields a char** (or a wchar_t** if it's wide), which is NOT what you want to pass -- if a Win32 function is expecting an LPSTR (i.e. a char*) and you pass it a char** cast to a char*, much badness will result. The compiler will not let you pass char** to a function expecting a char* without a cast -- using a cast to silence the compiler is WRONG, since the compiler is trying to tell you something important.

If you can't pass the parameter you want to in this case without casting, you're almost certainly passing it wrong. Fix the code so that you don't need a cast.

Adam Rosenfield
You and I were both too late. While we were typing, an answer was already accepted, saying that this very likely bug-ridden code should remain very likely bug-ridden. What a waste of our efforts.
Windows programmer
Unfortunately, the Windows API sometimes really does require seemingly bad casts like this. FormatMessage is an example.
Josh Kelley
@Windows programmer: So true, *sigh*@Josh Kelley: True, especially with regards to certain Windows messages. WPARAM and LPARAM can be anything under the sun. But, without the context of the particular function the OP is trying to call, I'm assuming the worst.
Adam Rosenfield
Yeah I just gave that as an example, the question is more about the style, not the specific example, so I think I marked the correct answer properly, but I've upvoted this as it's useful too. Thanks.
ApplePieIsGood
A: 

If lpMsgBuf is already a pointer to a T-string and if the API expects the pointer to point directly to a T-string then you shouldn't use any cast at all. In other words if the data type is already correct then it's a good idea not to use unnecessary casts. The reason is that overuse of casts can blind you to bugs at the same time as the casts shut up the compiler.

If lpMsgBuf is already a pointer to a T-string and if the API expects a pointer to pointer to a T-string but the API expects that pointer to pointer to be cast into type pointer to T-string (and the API will cast it back when using it), then you're doing it right.

If lpMsgBuf is a pointer to something else (of correct type) and the API expects a pointer to pointer to your type but the API expects these casting games, then you're doing it right.

If lpMsgBuf is a pointer to T-string and if the API expects a pointer to T-string, then by your use of the & operator you're constructing a pointer to pointer to T-string which the API doesn't expect, and by your use of a cast you're telling the compiler to turn that pointer to pointer into the type pointer to T-string even though the value still points to a pointer. So you successfully shut up the compiler but you still deliver garbage results to you or your customers.

So, without more details of which MSDN page is telling you to create a pointer to pointer and play casting games for which API, we can't guess whether you're doing it right, or whether you misread MSDN, or whether MSDN is telling you to write bad code.

Now, if the cast is actually right, then the choice of which syntax to use is dependent on your style in the rest of your program.

Windows programmer
+5  A: 

Rather than sprinkling my code with either old-style casts or new-style casts, I'd take advantage of C++'s operator overloading to add inline overloaded versions of the Windows API functions that take parameters of the proper types. (As long as this is documented for new developers, it hopefully won't be too confusing.)

For example, FormatMessage's fifth parameter is normally an LPTSTR, but if you pass the FORMAT_MESSAGE_ALLOCATE_BUFFER flag, the fifth parameter is a pointer to an LPTSTR. So I'd define a function like this:

inline DWORD WINAPI FormatMessage(
  __in      DWORD dwFlags,
  __in_opt  LPCVOID lpSource,
  __in      DWORD dwMessageId,
  __in      DWORD dwLanguageId,
  __out     LPTSTR *lpBuffer,
  __in      DWORD nSize,
  __in_opt  va_list *Arguments
) {
    assert(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER);
    return FormatMessage(dwFlags, lpSource, dwMessageId, dwLanguageId, static_cast<LPTSTR>(&lpBuffer), nSize, Arguments);
}
Josh Kelley
A: 

For the most part, MSDN Win32 sample code is compatible with C and C++. It's perfectly allowable (and was the standard practice at one point in time) to use plain old C for writing windows programs.

Since the C++ casts are not available in C, modifying the examples to take advantage of them would require maintaining two copies of sample code. Since the C code works as is in C++, it's easier just to leave the old-style casts in.

Eclipse