It depends on what you are trying to achieve. There is no meaningful "yes or no" answer to your question the way it is stated.
- If you are trying to create an abstract handle kind of type, implying that the user is not supposed to know or care what is hiding behind the type, then typedef-ing a pointer type is perfectly fine. The whole point is that today it might be a pointer type, and tomorrow it might become an integer type, and later it might become something else. This is exactly what pointer type typedefs are normally used for in most library interfaces.
You are saying that sometimes it is "not clear that a pointer is declared". But under this usage model that's exactly the point! It is supposed to be "not clear". The fact that the type happens to be an obfuscated pointer is none of your business. It is something that you don't need to know and not supposed to rely upon.
A classic example of this usage model is the va_list
type in the standard library. In some implementation it might easily be a typedef for a pointer type. But that's something you are not supposed to know or rely upon.
Another example would be the definition of HWND
type in Windows API. It is a typedef for pointer type as well, but that's none of your business.
- A completely different situation is when you are typedef-ing a pointer type as a form of shorthand, just to make the declarations shorter for not having to type the
*
character every time. In this case the fact that the typedef is (and will always be) standing for a pointer type is exposed to the user. Normally this usage is not a good programming practice. If the users will want to create an alias to avoid typing *
every time, they can do it by themselves.
This usage model usually leads to more obfuscated code for the reasons you already mentioned in your OP.
Example of this bad usage of typedefs can also be found in Windows API. Typedef names like PINT
follow exactly that flawed usage model.