This is a matter of style. You see this kind of code very frequently in the Windows header files. Though they tend to prefer the all upper case version instead of prefixing with a lower case p.
Personally I avoid this use of typedef. It's much clearer to have the user explicitly say they want a Foo* than PFoo. Typedef's are best suited these days for making STL readable :)
This can be appropriate when the pointer itself can be regarded as a "black box", that is, a piece of data whose internal representation should be irrelevant to the code.
Essentially, if your code will never dereference the pointer, and you just pass it around API functions (sometimes by reference), then not only does the typedef reduce the number of *s in your code, but also suggests to the programmer that the pointer shouldn't really be meddled with.
This also makes it easier to change the API in the future if the need arises. For instance, if you change to using an ID rather than a pointer (or vice versa) existing code won't break because the pointer was never supposed to be dereferenced in the first place.
typedef void (*SigCatcher)(int);
SigCatcher old = signal(SIGINT, SIG_IGN);
Otherwise, I find them more confusing than helpful.
The struck-out declaration is the correct type for a pointer to the signal() function, not of the signal catcher. It could be made clearer (using the corrected SigCatcher type above) by writing:
That is, a SignalFunction is a pointer to a function which takes two arguments (an int and a SigCatcher) and returns a SigCatcher. And signal() itself is a function which takes two arguments (an int and a SigCatcher) and returns a SigCatcher.
In C this is very common as you are trying to disguise that an object is a pointer. You are trying to imply that this is the object that all your functions manipulate (we know it is a pointer underneath but it represents the object you are manipulating).
MYDB db = MYDBcreateDB("Plop://djdjdjjdjd");
MYDBDoSomthingWithDB(db,5,6,7);
CallLocalFuc(db); // if db is not a pointer things could be complicated.
MYDBdestroyDB(db);
Underneath MYDB is probably a pointer at some object.
In C++ this is no longer required.
Mainly because we can pass things around by reference and the methods are incorporated into the class declaration.
MyDB db("Plop://djdjdjjdjd");
db.DoSomthingWithDB(5,6,7);
CallLocalFuc(db); // This time we can call be reference.
db.destroyDB(); // Or let the destructor handle it.
Some time ago, i'd have answered "no" to this question. Now, with the rise of smart pointers, pointers are not always defined with a star '*' anymore. So there is nothing obvious about a type being a pointer or not.
So now i'd say : it is fine to typedef pointers, as long as it is made very clear that it is a "pointer type". That means you have to use a prefix/suffix specifically for it. No, "p" is not a sufficient prefix, for instance. I'd probably go with "ptr".
The purpose with typedef is to hide the implementation details, but typedef-ing the pointer property hides too much and makes the code harder to read/understand.
So please do not do that.
If you want to hide implementation details (which often is a good thing to do), do not hide the pointer part. Take for instance at the prototype for the standard FILE interface:
here fopen returns a pointer to some structure FILE (which you do not know the implementation details for). Maybe FILE is not such a good example because in this case it could have worked with some pFILE type that hid the fact that it is a pointer.
However, that would only work because you never mess around with the content that is pointed to directly. The moment you typedef some pointer that you some places modify the code becomes very hard to read in my experience.
Consider the tagless concrete (not opaque) structure type definition:
typedef struct { int field1; double field2; } *Information;
The details of the members are completely tangential to this discussion; all that matters is that this not an opaque type like typedef struct tag *tag; (and you can't define such opaque types via a typedef without a tag).
The question raised is 'how can you find the size of that structure'?
The short answer is 'only via a variable of the type'. There is no tag to use with sizeof(struct tag). You can't usefully write sizeof(*Information), for example, and sizeof(Information *) is the size of a pointer to the pointer type, not the size of the structure type.
In fact, if you want to allocate such a structure, you can't create one except via dynamic allocation (or surrogate techniques that mimic dynamic allocation). There is no way to create a local variable of the structure type whose pointers are called Information, nor is there a way to create a file scope (global or static) variable of the structure type, nor is there a way to embed such a structure (as opposed to a pointer to such a structure) into another structure or union type.
You can — must — write:
Information info = malloc(sizeof(*info));
Apart from the fact that the pointer is hidden in the typedef, this is good practice — if the type of info changes, the size allocation will remain accurate. But in this case, it is also the only way to get the size of the structure and to allocate the structure. And there's no other way to create an instance of the structure.
Is this harmful?
It depends on your goals.
This isn't an opaque type — the details of the structure must be defined when the pointer type is typedef'd.
It is a type that can only be used with dynamic memory allocation.
It is a type that is nameless. The pointer to the structure type has a name, but the structure type itself does not.
If you want to enforce dynamic allocation, this seems to be a way to do it.
On the whole, though, it is more likely to cause confusion and angst than enlightenment.
Summary
It is, in general, a bad idea to use typedef to define a pointer to a tagless stucture type.
Well, first of all, you simply exchange a single character * for another single character p. That is zero gain. This alone should keep you from doing this as it is always bad to do extra stuff that's pointless.
Second, and that is the important reason, the * carries meaning that is not good to hide. If I pass something to a function like this
I do not expect the meaning of myBar to be changed by passing it to foo(). After all, I'm passing by value, so foo() only ever sees a copy of myBar right? Not when SomeType is aliased to mean some kind of pointer! Especially when that pointer acts as a reference to some kind of object whose value is basically the meaning of the pointer: I won't care that the pointer itself does not change (due to pass-by-value), I'm interested in whether the object changes or not (the object behind the pointer).
This applies both to C pointers and C++ smart pointers: If you hide the fact that they are pointers to your users, you will create confusion that is totally unnecessary. So, please, don't alias your pointers.
(I believe the habit of typedefing pointer types is just a misguided attempt to hide how many stars one has as a programmer http://wiki.c2.com/?ThreeStarProgrammer .)
There are a couple constructs that some other answers alluded to, and that is pointer-only types. There are a couple pointer-only type constructs that come to mind. If anyone thinks of more I'll add them to the list.
Opaque Types
These are types where the type's implementation is totally hidden to the user. You will typically see a structure typedef in the header, but no implementation of that struct. Because of that you cannot dereference values of these types. All functions that operate on this type take pointers to these types. It is appropriate to add the pointer to the typedef in these situations. You often see these called "handle" types.
Another pointer-only type are types that are defined with flexible array members (FAMs). The last member in a FAM type is an unconstrained array. You are intended to dynamically allocate storage for these types and the flexible array is treated as inline with the structure. You can access fields in a FAM type, but cannot dereference the whole object. It is also appropriate to add the pointer to the typedef here.