Is it a good idea to typedef pointers?

43,851

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 .)

Share:
43,851
Unknown
Author by

Unknown

Updated on July 08, 2022

Comments

  • Unknown
    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
    hbw about 15 years
    Real world example: in OS X, the CoreFoundation framework makes extensive use of this technique, referring to them as "opaque" data types.
  • TOMKA
    TOMKA about 15 years
    If 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
    Martin York about 15 years
    Thta's because the Win32 is a C API and it is common in C not C++
  • hbw
    hbw about 15 years
    I 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
    Adam Rosenfield about 15 years
    Also 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
    Jonathan Leffler about 15 years
    Counter example: FILE *fp? Actually, I agree with you, but there is ample precedent for the contrary.
  • Sad Developer
    Sad Developer about 15 years
    2 dreamlax: it is still less readable and consistent code, declaring two variables of different types o one line.
  • TOMKA
    TOMKA about 15 years
    The question is tagged both C and C++, what's your point exactly?
  • MSalters
    MSalters about 15 years
    'Course, if you do this, you don't name the opaque type "pFoo".
  • Prasanth Kumar
    Prasanth Kumar about 15 years
    But 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
    David Thornley about 15 years
    Unless 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
    Sad Developer about 15 years
    I think that '''int *pointer, *pointer2''' is still vulnerable to mistakes.
  • Benoît
    Benoît about 15 years
    Good point. I was trying to add some pros to the list of cons that had been said against typedef'ing pointers...
  • sigjuice
    sigjuice about 15 years
    Does this typedef with less punctuation work? "typedef void SigCatcher(int, void (*)(int))(int)"
  • Jonathan Leffler
    Jonathan Leffler about 15 years
    No; gcc says "error: SigCatcher declared as function returning a function".
  • Artelius
    Artelius over 14 years
    What Roalt meant to say was: 'int *pointer1' instead of 'int* pointer1'.
  • Matt Joiner
    Matt Joiner almost 14 years
    Oh wow, I never considered that FILE * was completely unnecessary. It would have been nice if they typedef'd that long ago.
  • Matt Joiner
    Matt Joiner almost 14 years
    @Daniel Daranas: int *p1 = NULL, *p2 = NULL;
  • Prasanth Kumar
    Prasanth Kumar almost 14 years
    @Matt Joiner You're right. Although I usually use two lines for that anyway.
  • sigjuice
    sigjuice over 13 years
    I just came across as even simpler typedef'd declaration of signal() freebsd.org/cgi/man.cgi?query=signal
  • Jonathan Leffler
    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 my SigCatcher, and yes, it simplifies the declaration of signal() enormously.
  • sigjuice
    sigjuice over 13 years
    cool. The equivalent declaration with the explicit * does not look so bad, IMHO. typedef void SigCatcher(int); extern SigCatcher *signal(int, SigCatcher *);
  • Admin
    Admin about 10 years
    Sure, but one would never go about writing list<const ordinary_type>, as it wouldn't work anyway, so there is no confusion.
  • Dan Hook
    Dan Hook about 10 years
    I'm not sure what you mean by ordinary_type. list<const SomeStruct*> is perfectly valid as const SomeStruct* is CopyAssignable.
  • Lundin
    Lundin over 8 years
    Typical 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
    Lundin about 8 years
    It 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
    rbaleksandar about 8 years
    Note also that typedef-ing a pointer can dramatically increase readability. Imagine you have std::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 nice typedef can make working and also reading the code a more pleasant experience.
  • chqrlie
    chqrlie almost 8 years
    @MattJoiner: the reason FILE* was not typedef'd as an opaque pointer is to allow macros such as getc() and putc() to manipulate the FILE structure directly and avoid the function call overhead in most cases.
  • chqrlie
    chqrlie almost 8 years
    This 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 notation LPPOINT ptr; was nothing more than that, a handy abbreviation for POINT FAR *ptr;, FAR expanding to far and later to __far. All this is quite inelegant, but it used to be even worse.
  • rbaleksandar
    rbaleksandar over 7 years
    Dunno about that. I mean if you have a pointer to let's say Device and you typedef it to Device_Ptr (instead of having to use Device *) 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
    Alex D about 6 years
    @rbaleksandar again it's ok if Device* is an opaque handle.
  • PSkocik
    PSkocik over 5 years
    +1. Another reason is there will be no typesystem protection from void *vp=/*...*/; foo(vp); or foo(0);. (Typedefs for enums and numerical typedefs for things that should never ever show up as numbers have similar problems).
  • Aconcagua
    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
    Aconcagua over 5 years
    In 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
    Aconcagua over 5 years
    Totally 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
    Fabio says Reinstate Monica over 5 years
    Could you please add a link to the article you mentioned? Besides, he's a man! :-)
  • dgnuff
    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
    Christoffer Bubach almost 4 years
    As 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 or myTypeRef over that star any day. :P
  • Gabriel Staples
    Gabriel Staples over 3 years
    Some 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
    Aposhian almost 3 years
    Even 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 of myBar (which is an address) still cannot be changed by foo, but the value pointed to by myBar can.
  • cmaster - reinstate monica
    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 to Fraction, the statements Fraction a = fraction(84, 2); printFrac(a); doSomething(a); printFrac(a); could yield confusing output. With Fraction* a = fraction(84, 2); it is clear that doSomething(a) may change the meaning of a by changing the object.
  • Aposhian
    Aposhian almost 3 years
    Yes, 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
    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
    tstanisl over 2 years
    Actually you could get the size without an object by applying sizeof on "dereferenced" NULL cast to Information. Try sizeof(*(Infomation)0).
  • luser droog
    luser droog almost 2 years
    Yes! Dear god! Somebody has a sensible view.