Ask HN: In C, why is the * operator both reference and type casting?

  • I imagine the rationale was something like: how do we indicate that types are references to memory? Let's be concise and use the asterisk after the type of the memory.

    How do we dereference an address? Since it only makes sense that types with an asterisk will be dereferenced, let's use an asterisk like we did in the type declaration. There, we have uniformity.

    Oh wait, f-. What about if we want the address of something on the stack? Oh, maybe use the ampersand, and then that returns a pointer just like a pointer to something on the heap. Awesome! Let's even extend that ampersand to return the address of anything. Dereferenced pointers. What have you.

    And yet, it's not completely symmetrical. Hence, pointers not being completely intuitive.

    In addition, the ampersand as 'reference' is another completely unrelated syntax convenience. Which of course makes the language even slightly less symmetrical.

    But, once you understand exactly what it's doing -- and your mind will adapt until it seems completely intuitive -- it is quite concise.

    But the trick is that it's not concise like s-expressions. There's no clear symmetry. A lot of C (and even more C++) is simply syntax.

  • The second * has nothing to do with type-casting -- it is part of the type identification. The operator performing the typecast is the pair of parentheses.

    Consider: int and int * are two different types. So typecasting to int when you really mean int * is completely different.

  • The * in the parentheses is part of type name and it indicates that the type being named is the sort of type to which it makes sense to apply the run-time * operator.

  • Substitute the obvious character for $%^& below -- I couldn't figure out how to convince HN that I wasn't just delimiting italics.

    What was the historical reason for using the $%^& operator for both things?

    I think the argument was that it allows you to say "foo is a pointer to an integer" == (int $%^&) foo == int ($%^& foo) == "that which is pointed to by foo, is an integer".

  • (Mentally replace all ^s with asterisks in the following:)

    I don't understand your C code. What is "(int foo^)" supposed to do? It looks almost like a cast, but "int foo" isn't a valid type in C. Maybe "(struct foo^)" or "(int^)"?