Should I avoid typedef, try to use primitive names

2020-07-23 06:26发布

I'm not sure of the vocabulary here, but hopefully I can make myself understood.

As I'm working through the winapi with a less-than-rock-solid knowledge of C++, I find a lot of typedef stuff that, for me, seems to overcomplicate the issue and add one more thing I have to remember.

For example, UINT instead of unsigned int, HBITMAP which turns out is just a HANDLE, and lots of others.

My question is, can / should I substitute the more generic version of the type when possible, and just cast it down when it's needed (and, what's this called)?

For example, I'd like to write

  • void SomeFunction(unsigned int some_int) { ... } instead of void SomeFunction(UINT some_int) { ... }

  • HANDLE hBMP = LoadImage(...); ImageList_Add(... (HBITMAP) hBMP ...); instead of HBITMAP hBMP = ...

Is this good for newcomers, bad practice in general, or what?

5条回答
姐就是有狂的资本
2楼-- · 2020-07-23 06:48

1) The Win32 API is actually C, not C++.

The distinction becomes more important if you consider stuff like MFC or ATL, both of which are "object-oriented", C++-only APIs. And both of which are mercifully becoming (have become?) obsolete.

2) Microsoft likes to use lots of macros and typedefs. I can't say whether that's "good" or "bad". It's simply a fact of life. And it'll become second nature to you if you work with Windows for any length of time.

3) Most importantly - Yes: you should definitely follow the Microsoft conventions when you use the Microsoft APIs. Using "HANDLE" when the MSDN page says "HANDLE" is a Good Thing. Similar advice holds for "LPxxx", "TRUE", "FALSE", "INVALID_HANDLE", "HRESULT" etc etc. If that's what it says in MSDN, then that's what you should use.

Not only will it make your code more readable ... but, surprisingly often, it can also prevent subtle bugs you might cause by "second guessing" the "true type".

Do not try to "second guess" the types. It's just a Bad Idea.

Following the standard conventions will make life easier, safer, more reliable and more portable.

IMHO...

查看更多
闹够了就滚
3楼-- · 2020-07-23 06:51

Please don't typedef the obvious (i.e. UINT for unsigned int). Rather, typedef to convey meaning. UINT no better than unsigned int (some may argue that it's shorter, but seriously, it's not that much shorter).

A typedef for a long name (like a typedef for std::map<unsigned int, flost>::const_iterator) is, in my opinion, okay, because it improves readability. UINT... not so much.

A typedef to convey specific meanings for specific types/uses (like HANDLE) are decent. HANDLE is, in my opinion, better than using raw void* because a) I don't care if HANDLE is a void*, b) it conveys its purpose.

A typedef for portability is nice (like a typedef for a 32-bit signed integer), as it allows for easier transitions between platforms/compilers.

查看更多
Viruses.
4楼-- · 2020-07-23 07:06

Is this good for newcomers, bad practice in general, or what?

It is a bad practice. You should not use the actual types.

The typedef's are usually for portability on different platforms & compiler implementations. So you should refrain yourself from using actual types instead of the typedef'ed name. Using actual types will make your code more tightly coupled to the platform & compiler implementation you use, in fact it may not work correctly if this combination changes.

Also, the typedefed names are more intuitive and widely known to programmers than the actual types, which is an additional reason why you should stick to those.

查看更多
做个烂人
5楼-- · 2020-07-23 07:08

Typedefs are not only useful for portability, but also for future proofing. If MicroSoft decides at some point that UINT should be a typedef for an unsigned long int instead of an unsigned int then using UINT will make sure your code continues to work. This type of change is highly unlikely, especially with code from large companies like MS, but the idea still holds: typedefs are good for many kinds of abstraction. They are by no means bad, but you can occasionally find examples of poor usage. If you are using someone else's API, always use their typedefs. They probably have a good reason for the abstraction.

查看更多
冷血范
6楼-- · 2020-07-23 07:10

There are several reasons for using a typedef.

  1. abbreviating some type: typedef unsigned int UINT
  2. portability: typedef int INT64
  3. readability: typedef HANDLE HBITMAP

I'd rather read HBITMAP hBitmap = ... than HANDLE hBitmap = ... for the same reason that I would (in general) not write Animal dog = new Dog() because being more specific can help the reader of your code and you're not losing anything here because according to the Liskov substitution principle you can use the dog instance everywhere you can use an Animal instance.

You might also consider using BOOST_STRONG_TYPEDEF if you are using C++ with Boost, this basically creates a simple class, thus, giving you a real new type (which means that you cannot mix the uses like you can with HANDLE and HBITMAP.


What you describe as casting is not really casting, because the types are identical, a typedef only creates an alias, not a new type. So, writing

HANDLE hOtherBitmap = /* some code */;

HBITMAP hBitmap = (HBITMAP) hOtherBitmap;

is like writing

int i = /* some value */;

int k = (int) i;

查看更多
登录 后发表回答