Is it a good idea to typedef pointers?
Solution 1
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.
Solution 2
Not in my experience. Hiding the '*
' makes the code hard to read.
Solution 3
The only time I use a pointer inside the typedef is when dealing with pointers to functions:
typedef void (*SigCatcher(int, void (*)(int)))(int);
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:
typedef SigCatcher (*SignalFunction)(int, SigCatcher);
Or, to declare the signal()
function:
extern SigCatcher signal(int, SigCatcher);
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
.
Solution 4
This can help you avoid some errors. For example in following code:
int* pointer1, pointer2;
pointer2 is not an int *, it is simple int. But with typedefs this is not gonna happen:
typedef int* pInt;
pInt pointer1, pointer2;
They are both int * now.
Solution 5
My answer is a clear "No".
Why?
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
void foo(SomeType bar);
void baz() {
SomeType myBar = getSomeType();
foo(myBar);
}
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 .)
Unknown
Updated on July 08, 2022Comments
-
Unknown almost 2 years
I looked through some code and noticed that the convention was to turn pointer types like
SomeStruct*
into
typedef SomeStruct* pSomeStruct;
Is there any merit to this?
-
hbw about 15 yearsReal world example: in OS X, the CoreFoundation framework makes extensive use of this technique, referring to them as "opaque" data types.
-
TOMKA about 15 yearsIf you put the * touching pointer1 rather than touching "int", the declaration makes much more sense that pointer2 is not a pointer, just an int.
-
Martin York about 15 yearsThta's because the Win32 is a C API and it is common in C not C++
-
hbw about 15 yearsI think C programmers would argue that using the dereferencing operator when declaring a pointer variable is more of an idiomatic thing. For examine, in K&R, they say: "'int *ip' intended as a mnemonic; it says that the expression '*ip' is an int."
-
Adam Rosenfield about 15 yearsAlso in OS X: pthread_t is an opaque type; it is typedef'ed to be a pointer to a 'struct _opaque_pthread_t', which is itself an opaque array of bytes.
-
Jonathan Leffler about 15 yearsCounter example: FILE *fp? Actually, I agree with you, but there is ample precedent for the contrary.
-
Sad Developer about 15 years2 dreamlax: it is still less readable and consistent code, declaring two variables of different types o one line.
-
TOMKA about 15 yearsThe question is tagged both C and C++, what's your point exactly?
-
MSalters about 15 years'Course, if you do this, you don't name the opaque type "pFoo".
-
Prasanth Kumar about 15 yearsBut everyone knows this syntax, and it's best to declare and initialize one variable at a time anyway... I seldom if ever write int *pointer1, *pointer2; because in the next line you have two nice pointers with undefined value.
-
David Thornley about 15 yearsUnless you don't intend it to be used as a pointer, in which case you can name it what you will. If it's just used to pass stuff around (like a C FILE *), does it matter exactly what it is?
-
Sad Developer about 15 yearsI think that '''int *pointer, *pointer2''' is still vulnerable to mistakes.
-
Benoît about 15 yearsGood point. I was trying to add some pros to the list of cons that had been said against typedef'ing pointers...
-
sigjuice about 15 yearsDoes this typedef with less punctuation work? "typedef void SigCatcher(int, void (*)(int))(int)"
-
Jonathan Leffler about 15 yearsNo; gcc says "error: SigCatcher declared as function returning a function".
-
Artelius over 14 yearsWhat Roalt meant to say was: 'int *pointer1' instead of 'int* pointer1'.
-
Matt Joiner almost 14 yearsOh wow, I never considered that
FILE *
was completely unnecessary. It would have been nice if they typedef'd that long ago. -
Matt Joiner almost 14 years@Daniel Daranas:
int *p1 = NULL, *p2 = NULL;
-
Prasanth Kumar almost 14 years@Matt Joiner You're right. Although I usually use two lines for that anyway.
-
sigjuice over 13 yearsI just came across as even simpler typedef'd declaration of signal() freebsd.org/cgi/man.cgi?query=signal
-
Jonathan Leffler over 13 years@Sigjuice: even without going to the BSD page (which I didn't do until after I'd edited the material), I saw huge problems with my answer, which are now fixed. And what BSD calls
sig_t
matches mySigCatcher
, and yes, it simplifies the declaration ofsignal()
enormously. -
sigjuice over 13 yearscool. The equivalent declaration with the explicit * does not look so bad, IMHO. typedef void SigCatcher(int); extern SigCatcher *signal(int, SigCatcher *);
-
Admin about 10 yearsSure, but one would never go about writing
list<const ordinary_type>
, as it wouldn't work anyway, so there is no confusion. -
Dan Hook about 10 yearsI'm not sure what you mean by
ordinary_type
.list<const SomeStruct*>
is perfectly valid asconst SomeStruct*
is CopyAssignable. -
Lundin over 8 yearsTypical example of defending bad practice with even more bad practice. Never declare more than one variable on a single line, because there is never a reason to do so, period. It will only lead to bugs. And the whole "pointer touching" debate is nonsense, because if you write good code in the first place, the location of the
*
doesn't matter. -
Lundin about 8 yearsIt should be noted that this is not common practice in C either, the Win API is pretty much the only well-known C library that does this. It also uses Hungarian notation. It is a very obscure library style-wise, it is not something you should bring up as canon.
-
rbaleksandar about 8 yearsNote also that
typedef
-ing a pointer can dramatically increase readability. Imagine you havestd::map<int, std::map<std::string, std::vector<int> > >
as a variable. If you have to use define a lot of such variables in different places of your code using a nicetypedef
can make working and also reading the code a more pleasant experience. -
chqrlie almost 8 years@MattJoiner: the reason
FILE*
was not typedef'd as an opaque pointer is to allow macros such asgetc()
andputc()
to manipulate the FILE structure directly and avoid the function call overhead in most cases. -
chqrlie almost 8 yearsThis notation goes back to the origin of Windows, 30 years ago, in the Intel 16 bit segmented architecture.
LP
stands for long pointer and the shorthand notationLPPOINT ptr;
was nothing more than that, a handy abbreviation forPOINT FAR *ptr;
,FAR
expanding tofar
and later to__far
. All this is quite inelegant, but it used to be even worse. -
rbaleksandar over 7 yearsDunno about that. I mean if you have a pointer to let's say
Device
and youtypedef
it toDevice_Ptr
(instead of having to useDevice *
) or similar it's quite readable. I see a lot of well matured and pretty big libraries that do that. Especially in C++ if you add templates this can spare your fingers quite the typing. -
Alex D about 6 years@rbaleksandar again it's ok if Device* is an opaque handle.
-
PSkocik over 5 years+1. Another reason is there will be no typesystem protection from
void *vp=/*...*/; foo(vp);
orfoo(0);
. (Typedefs for enums and numerical typedefs for things that should never ever show up as numbers have similar problems). -
Aconcagua over 5 years@rbaleksandar That example is aliasing a type, not the pointer. And the pointer to such a map better shouldn't be aliased.
-
Aconcagua over 5 yearsIn addition to @JonathanLeffler: Best if - in the public header - the type for the opaque pointer was only declared, but defined elsewhere:
struct XYZ; typedef struct XYZ* Handle;
- if the implementation is needed accross several compilation units, it might be defined in a separate, private header... -
Aconcagua over 5 yearsTotally agree on the given use case, would appreciate, though, if answer was a bit more explicit about that this should be the exceptional case (wheras, in general, if the pointer is intended to be dereferenced, it should better not be aliased).
-
Fabio says Reinstate Monica over 5 yearsCould you please add a link to the article you mentioned? Besides, he's a man! :-)
-
dgnuff over 4 years@Azat Ibrakov It's a minor point, but while Herb is definitely a guy, the Guru he writes about is female. Hence it is appropriate to refer to her in the feminine. Yeah, I know she's effectively an alter ego for Herb, but if you read the entire series, including the story told in the first 20 or so articles, it makes sense for her to be who she is.
-
Christoffer Bubach almost 4 yearsAs a C n00b I think C's pointer syntax is an abomination - only liked by those unfortunate souls that already spent 10+ years learning to like it. I'd take
myTypePtr
ormyTypeRef
over that star any day. :P -
Gabriel Staples over 3 yearsSome people might want to see an example of a "black box" pointer which shouldn't be directly meddled with. So, here's a full example I wrote of an "opaque pointer" (or: pointer to an opaque struct) in C which demonstrates this perfectly, including the
typedef
of the opaque pointer. Opaque C structs: how should they be declared? -
Aposhian almost 3 yearsEven if you pass the pointer to a function, the pointer
myBar
itself is still being copied, even if the data that it points to is not. So the value ofmyBar
(which is an address) still cannot be changed byfoo
, but the value pointed to bymyBar
can. -
cmaster - reinstate monica almost 3 years@Aposhian Yes. So? - My point is that a pointer usually serves as a proxy for some object in memory. The semantics of the pointer are pretty much the semantics of the object behind it, and those can be changed by any function receiving the pointer. For instance, if you had a type
struct _fraction
and typedefed its pointer toFraction
, the statementsFraction a = fraction(84, 2); printFrac(a); doSomething(a); printFrac(a);
could yield confusing output. WithFraction* a = fraction(84, 2);
it is clear thatdoSomething(a)
may change the meaning ofa
by changing the object. -
Aposhian almost 3 yearsYes, you are right. And I agree that typedef-ing pointers is generally an obfuscation. I just don't want anyone reading this to conflate the meaning/semantics of a pointer and its value, which are separate and distinct. Remembering that difference is critical when reassigning pointer variables, or using pointers-to-pointers.
-
cmaster - reinstate monica almost 3 years@Aposhian Ah, now I see. Well, I've added some words at the point in question in the hope of making my meaning clearer. Thanks for pointing that out.
-
tstanisl over 2 yearsActually you could get the size without an object by applying
sizeof
on "dereferenced"NULL
cast toInformation
. Trysizeof(*(Infomation)0)
. -
luser droog almost 2 yearsYes! Dear god! Somebody has a sensible view.