Quzah covered the variable declaration and the typedef pretty well. I'll get to the prototype in a minute, but a huge part is simply because it was designed that way. Like Quzah said, it could've been the other way, but it isn't.
Your syntax is slightly off. There shouldn't be a comma there, which might be part of your association issues. And yes, it is before a type, but it's not before the type it's connected to. It actually is after the type, it's just after the old type name, not the new one. The correct syntax is:
Originally Posted by Syndacate
Note that I left old type specifier with spaces to show you can have a multi-word type specifier, such as "struct foo_s", but the new_type_name must be a valid C identifier, like "foo_t". What you're really saying with the typedef is (pay attention to the colors):
typedef old type specifier new_type_name;
Yeah, that * stays on the left. The old type is a char pointer, or char *. The new name you want as a short hand is pchar. If you put it to the right of pchar, it just wouldn't make sense. Now, continuing on with pchar, we know that:
typedef char * pchar;
int x, y;
// is the same as
So both s and t are of type pchar. That's the way the language was designed.
pchar s, t;
// is the same as
Well, your misunderstanding may come from the asterisk eluding your understanding. But the lack of a parameter name doesn't really allude to the fact that the * should be bound more to the type than the variable name. Function parameters are different than regular variable declarations. Each one must specify a full type and be separated by commas. The name is mandatory in the declaration, but optional in prototypes because of what prototypes were designed for. C reads files top-down, an is only aware of things that it has already seen. So if you declare a function after you use it, or in another file to be linked in later, you need a prototype so the compiler can check the parameter count, parameter type and return type. The names of the variables don't matter in the prototype, it's just so the compiler can check if you're using it right. It doesn't care what you call it, as long as it's the right type.
Then there's prototypes - just the prototype - in C, no variable name is required, so your prototypes can look like this:
Again, eluding to the concept that the asterisk (the property) applies to the type, not the variable.
There's no inconsistency, except the one you made up. The * always goes with the variable name, even when it's "built in" to a typedef or the name is "invisible" in a prototype.
Can somebody explain this MESS to me? I just see so much inconsistency, and I never really cared about it, but now it's starting to bother me for some reason :-\.
Search! There, I told you...whaddaya gonna do about it? Yeah, that's what I thought.
And plz don't tell me to search, all the searching I've done has only told me that the asterisk applies to the variable, not the type - which I know, but that's not answering my question.
Not entirely true, considering your commas-in-typedefs issue above. Also, Quzah's examples showed you specific things you wouldn't be able to do if you had it your way. You should probably be a little less curt with those who are trying to help you.
Originally Posted by Syndacate
It's not inconsistent. You have 3 gramatically separate elements. Just because all 3 things specify a type for something doesn't mean they must behave identically. The syntax for all variable declarations is consistent. So is all typedef syntax. So is all prototype syntax. But the 3 are different things, so they are each different from eachother.
What I'm not aware of is the rationale behind both A) The inconsistency of the syntax
"as it should" really ought to be "like I want it to". If you feel that strongly about an arbitrary decision that has no bearing on the usefulness of the language, then programming isn't for you. If you think it cripples the C language, too bad, nobody's gonna change after 40 years, but you certainly could write the ISO committee if it makes you feel better. If it just plain bugs you, then there are a bunch of other languages besides C you can pick from that don't even use an asterisk or give you pointers to mess with, or types, or functions.
and B) The idea that the asterisk binds to the variable when it realistically shouldn't - it has nothing to do with the variable, you're declaring the type to be a pointer, it is affecting the type, not the variable. This is reflected, as I showed above, in both typedefs, as well as function prototypes, where the asterisk affects the type, NOT the variable - as it should.
Like Quzah said, typedef'ing pointers is nasty, and nobody likes it (okay, a few people do, but most experienced, professional programmers avoid it). Yes, you see it in industry, but lots of bad practices occur in industry. Industy is not the gold standard. The reason it's disliked is that it makes it hard to determine just how many levels of indirection (pointerness) you have in a given variable/type -- clear, easily maintainable code is the goal, not saving characters in source files. The use is acceptable if the typedef'ed pointer points to a completely opaque type/struct.
Also, for the "Never typedef a pointer. No one likes that." comment: It's done in industry all the time, especially when declaring the typedef wrap around structs. Things like
typedef FILE *FHANDLE;
are also extremely common.