9

For a long time I was of the opinion that pointer variables in C/C++ should have the asterisk immediately after the type name (e.g. int* foo).

Eventually I became convinced that it makes more sense to have it before the variable (e.g. int *foo).

Now I find routines that return pointers look weird, e.g.: void *allocate_something() so I am considering adopting the original style I used.

The only advantage of having the asterisk before the variable name I am aware of is that it is easier to remember to add an asterisk if you define more than one pointer on that line.

Anyone else find it hard to settle on code style guidelines for their own personal projects?

Comments
  • 4
    You can also do:
    void * allocate_something()

    I think I write like this when I just write for myself.

    But I'm fine with either

    void* allocate()
    void * allocate()
    void *allocate()
  • 0
    You should also consider smart pointers though.

    Inside #include <memory>

    std::shared_ptr<type> allocate()

    Or unique when possible.
  • 0
    @FrodoSwaggins Yes I suppose you can typedef the pointer away and have something like:

    typedef int* int_ptr;

    Then it's obvious just from the name:

    int_ptr foo;

    Though there's a separate argument for/against that. e.g. in Windows this kind of thing happens a lot, but reading the Linux kernel style guidelines previously, there is a lot of emphasis on making things obvious and avoiding this kind of typedef.

    I've grown accustomed to seeing * and immediately thinking "yep, that's a pointer", but equally typedef'ing something with a meaningful name (e.g. a _ptr suffix) doesn't make it any less clear.
  • 0
    @FrodoSwaggins Ah, sorry, I misunderstood the "think about type casts" part. And yes I also only bother to typedef for struct/enum in most cases, mainly to avoid needing to specify them everywhere in C.

    For opaqueness it works quite nicely as you can typedef a struct in a header, then actually define the struct in the .c file. For a while I've had create/destroy routines where the creation routine provides a pointer to such a type so the implementation is truly hidden. Just means you can't store such a struct on the stack (since the size of it cannot be known outside the implementation).
  • 1
    I think of pointers as part of the type, it's not an int it's an int pointer, also when you need to dereference multi level pointers, having the asterisk on the type makes more sense imo
  • 0
    How do your pointer casts look? (int*)a or
    (int *)a (or their respective C++-style eqivalent)?

    I use
    int *a; and
    int *b(void); but cast with
    (int*)c
  • 0
    I used to use (int*)x but when I switched to declaring variables as int *x I started casting as (int *)x which I kinda liked the look of.

    I think I tried (int*) x at some point as well but that feels like the cast is somehow separate to the variable being casted.
  • 1
    I always use the asterisk at the identifier, never at the type, so:
    int *x;
    (int *)
    void *function()...

    This is for two reasons, first when declaring variables:
    int *x, y; vs int* x, y;
    It is more clear that x is an int * and y is an int.

    Secondly compiler attributes never can be between identifier and asterisk, so
    void function(int __attribute__((unused))*x) will work but
    void function(int *__attribute__((unused))x)
    Will yield an error, which is the proof for me that the asterisk does only belong to the identifier.
  • 0
    @JustKidding Personally I've not used __attribute__((unused)) before. Giving it a try now (with gcc 5.1.0), both versions compile without error for me. Out of interest, what error do you get?

    I suspect you can also put the attribute after the variable too:

    void function(int *x __attribute__((unused)))

    void function(int* x __attribute__((unused)))
  • 0
    int *one, *two, *three;

    I think this makes the Answer quite clear. I discovered this after using the

    int* one;

    Syntax because I always thought "Hey, it's a pointer type... Belongs with the type declaration."

    The cleanest way is

    typedef intptr int*;

    That way, this works:

    intptr one, two, three;

    And the type is clearly defined, no room for a missing asterisk error.
  • 0
    @nightowl i have not tried your version but in your example neither case interferes with the asterisk. But you still can't place anything (except a space) between asterisk and identifier which means that they belong to each other.
  • 0
    @JustKidding That's the thing - I tried both of your examples and they worked for me. So I was curious what error it produces.
Add Comment