View Full Version : Why int *foo instead of int* foo?
poita
06-04-2007, 07:54 AM
This has always bugged me: why is it common practice to put the pointer symbol (*) beside the identifier instead of the type? I know that both ways are perfectly legal but why is the less logical one (at least for me) the most common?
It seems logical to me that a declaration of this sort should go:
<Type><Space><Identifier>;
The * is part of the type, not part of the name.
When you say int *foo you are creating a variable "foo" that is of type pointer-to-int or as I would see it "int*".
Is it just become one of those habit things that have continued for consistency's sake or is there an actual reason that the * goes with the identifier instead of the type?
dave_
06-04-2007, 08:03 AM
Backwards compatibility... I think. I was at a conference where even stroustrup admitted it was a mistake
poita
06-04-2007, 08:23 AM
Because
int*
p,
q;
Ahh, I see.
IMO int* p,q should create 2 pointers, not a pointer and an int. That seems more logical to me.
.oisyn
06-04-2007, 09:26 AM
I usually type
int * foo; ^_^
The * is part of the type, not part of the name.
It depends how you look at it. When I write "int *foo" what I really want is the integer. The fact that this integer is accessed by a pointer is just a detail. As a matter of fact, writing "int foo" creates a pointer too. The integer will be created on the stack and to access it the stack pointer and the offset is needed (whether or not the compiler decides to keep the variable in a register is just another detail).
So you could regard the explicit indirection as more closely related to the way the variable name is used, than the type itself. int is the type, and *foo is how we access it.
Of course, these arguments are just 'excuses' to explain the somewhat odd semantics of what tbp illustrated... But it works for me! :lol:
I usually type
int * foo; ^_^
What's the result of multiplying int and foo? ;) That gets even more confusing with typedefs and classes with overloaded operators...
.oisyn
06-04-2007, 01:25 PM
The person that overloads operator*() that has side-effects rather than return a new value that can be assigned to something should be shot on sight ;)
dave_
06-04-2007, 01:33 PM
typedef char* foo;
const foo x;
typedef const char bar;
bar* y;
to add another confusion: is x the same type as y? ;)
just another example of confusing C++ syntax, it makes a lot more sense if you change where you place your const.
typedef char* foo;
foo const x;
typedef char const bar;
bar* y;
SamuraiCrow
06-04-2007, 02:46 PM
C and C++ are full of confusing syntax. I can see why some people would rather shell out the bucks for Blitz Basic than use Code::Blocks and MinGW for free.
Nautilus
06-05-2007, 07:24 AM
Ahh, I see.
IMO int* p,q should create 2 pointers, not a pointer and an int. That seems more logical to me.
I agree with you.
This demonstrates that the compiler parses the star (*) as part of the identifier, and not as part of the type.
The fact that no syntax error is raised when compiling int* Foo; is a bonus, although welcome.
Yet, I'd like to see modern compilers featuring the option to raise a syntax error (at least a warning) when [type]* [identifier], or the opposite, is found.
It would help to enforce the same coding convention throughout a team project.
Ciao ciao : )
.oisyn
06-05-2007, 07:39 AM
typedef char* foo;
const foo x;
typedef const char bar;
bar* y;
to add another confusion: is x the same type as y? ;)
const bar* z;
and what is z? ;)
flux00
06-07-2007, 07:29 PM
Is it possible in c++ to have a array of const ints, and differentiate that from a const array of ints?
What's the difference you are looking for? The array contains the ints and nothing else, so if the ints are const, the whole array should be const (and viceversa).
.oisyn
06-08-2007, 02:43 AM
Indeed. A pointer can have two "types of const" (the pointer itself can be const, and the object pointed to can be const), because you are allowed to alter both the pointer itself and the data pointed to.
You can't alter an array - only it's elements. So there's no such thing as a const array of non-const elements or vice versa, that doens't make any sense. The same with references. You can't alter references, so const references don't exist.
flux00
06-08-2007, 01:59 PM
hmm, if I wanted to create an array of abstract classes, would I just make an array of references to the abstract class?
class A
{
public:
virtual int get() = 0;
};
class B
{
public:
int get()
{
return 5;
}
};
class C
{
public:
int get()
{
return 8;
}
};
int main()
{
int len = 10;
(A&)* arr = new (A&)[len]; //?
}
.oisyn
06-08-2007, 02:58 PM
You can't create arrays of references - you'll need an array of pointers.
anubis
06-10-2007, 02:25 AM
Most of these oddities probably stem from pre ansi function parameter lists. When function parameters where declared outside of the actual function head like this :
void foo(a, b, c)
int a, b;
float c;
{
...
}
the logic must have been that the function gets n parameters of type int. Wheather the variables are pointers or arrays then was seen as additional information to the type, that goes with the variable name. But that's probably a bad explanation for something purely concidental as well :)
t0rakka
06-25-2007, 11:35 AM
It's a matter of preference, I prefer to think this way:
int* p; // pointer (to int) named p
I don't think like this:
int *p; // int (pointer to named p)
It's simple as that. I never declare more than one variable per line, so I get around the usual trap of:
int* a, b;
I never write..
int i, j;
.. either. I have a habit of initializing the variables, if possible, at declaration-- this comes from serious trauma at childhood: I learned assembly (z80) pretty much as the first programming language.
Second, when I (have to, like, at work) write C, I _try_ to initialize at declaration because I don't want to separate variables from their initialization by dozen or more lines of code. If there is that much code between the variable and assigning to one, then the function probably is too large anyway (or maybe not).
There is only one enemy (when writing C) to this scheme; asserts. Often you want to assert function arguments, well, duh?
void example(foo* bar)
{
assert( bar .. blablablablaaa );
int size = xxxComputeFapFactor(bar);
^ Anyone care to notice the error in above example? Oh yes, the assert before declaration. Question arises? Why not leave the assert to the xxxComputeFapFactor() then? A: becuase this is a *****ing example!
:) :)
Reedbeta
06-25-2007, 01:00 PM
In C99 you can do the declaration after the assert just fine.
kulik
06-26-2007, 05:23 AM
This is one of the few things that troubles me about C/C++. I always think of pointer as a datatype, but that's the opposite way to the compiler.
as stated above int* a, b declares one pointer, one instance.
I would welcome some gnu extension that would warn me about this as well, because I have experienced some hand bashing problems with it in the past (whole team staring at the code, nobody discovering that the variable wasn't a pointer)
t0rakka
06-26-2007, 10:33 PM
Reedbeta, knowledge of C99 doesn't help when it can't be used. Handheld.. ancient toolchains.. :( :(
Reality shapes the practise, for hobby coding @ home I use C++ (2003) without export, of course. It's available in standard but not in compiler(s) I use (g++ 4.x and VC++8)
We can't even use // comments in C, because *possibly* someone might use compiler that doesn't support them.. on and on.. :(
anubis
06-26-2007, 11:01 PM
The fact that this very problem has been fixed by moving array qualifiers to the type, in most languages that derive from c, is a sure sign, that it's just broken design in c...
flux00
06-27-2007, 05:42 PM
While we're on this topic (sort of) I was wondering why in the world my compiler wouldn't warn me about something like this:
float **func(float a, float b)
{
float **r = new float*[1];
r[0] = new float[2];
r[0][0] = a;
r[0][1] = b;
//no return statement
}
int main()
{
float **t = func(5, 6);
std::cout << t[0][0] << std::endl;
return 0;
}
And also...
class A
{
public:
A(const A &a) {}
};
class B
{
private:
A d;
public:
B(const A &a) : d(d) {}
//supposed to be d(a)
};
Both of these just caused my program to crash when they were used.
Reedbeta
06-27-2007, 07:43 PM
Which compiler are you using? Do you have all warnings turned on (-Wall in gcc, warning level 4 in VS)?
Borogove
06-27-2007, 10:00 PM
While we're on this topic (sort of) I was wondering why in the world my compiler wouldn't warn me about something like this:
float **func(float a, float b)
{
float **r = new float*[1];
r[0] = new float*[2];
r[0][0] = a;
r[0][1] = b;
//no return statement
}
int main()
{
float **t = func(5, 6);
std::cout << t[0][0] << std::endl;
return 0;
}
Both of these just caused my program to crash when they were used.
Your compiler sucks. VC2003 dies on r[0] = new float*[2]; with "error C2440: '=' : cannot convert from 'float ** ' to 'float *'; Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast". If I change that to "new float[2]" which makes more sense given the subsequent lines, I get "error C4716: 'func' : must return a value". Any good compiler should at least warn on the no-return.
.oisyn
06-28-2007, 02:28 AM
It's sad that the C++ standard states that a function returning a value without actually returning one using the return statement yields undefined behaviour, rather than being ill-formed.
The fact that this very problem has been fixed by moving array qualifiers to the type, in most languages that derive from c, is a sure sign, that it's just broken design in c...
It's really just a choice. In the early days of C programming I can imagine that they frequently needed only integers and pointers to integers. So it's handy to be able to write just one line for them. Besides, once you've accepted the convention to write the * to the variable name it's really what you expect. Just look at the * as decoration. You declare an int, and *foo is how you access it. foo is the undecorated variable name and you can do all sorts of arithmetic on it to access the ints at different addresses.
Also consider this:
int* foo;
*foo = 0;
If foo is of type integer pointer, then how does one access the integer pointed at by foo? By writing * in front of foo? Isn't that confusing? It's almost like writing int* *foo = 0;.
If you just write int *foo it's clear that *foo is the integer and foo, the undecorated variable name, is its address. Once you look at it this way there's really nothing "broken" about it at all, it was just a design choice. They could have made a different choice but I'm not so sure they would have been better... Anyway, everyone should just adhere to the convention of writing * next to the variable name to solve this age-long discussion. Yes that means you too .oisyn. ;)
.oisyn
06-28-2007, 06:11 AM
I'm sorry but now you're just making up arguments that coincidentally match the status quo to defend the design decision at that time, while in reality you don't exactly know what the reasons were :). Besides, the reasoning doesn't have anything to do with where to put the '*', which is just a matter of taste.
A counter example:
typedef int* intptr;
intptr foo, bar;
No troubles here, both foo and bar are of type int*. intptr is an alias for int*, int* is a complete type. So why can't I replace it with int*?
Kenneth Gorking
06-28-2007, 06:44 AM
Whoops...
kulik
06-28-2007, 10:05 AM
I think every compiler would warn you about the first one.
GCC didn't warn me about the second one when I tried (-Wall), but I think the warning would be void if you used references (not copy constructor in your constructor), it would be meaningless to have reference to itself, but probable.
flux00
06-28-2007, 10:56 AM
Did gcc warn you about the first, or would it simply not compile?
Which compiler are you using? Do you have all warnings turned on (-Wall in gcc, warning level 4 in VS)?
I'm using MinGW, and the little line
r[0] = new float[2];
was a bit of a typo, sorry. I'm not sure what warnings are turned on, probably just the default ones. The point of the first was that I had no return statement, and the point of the second was that a copy constructor could be invoked with an uninitialized variable. I'll try -Wall.
I'm sorry but now you're just making up arguments that coincidentally match the status quo to defend the design decision at that time...
True. But does it matter? My point is that complaining about the syntax doesn't help. It's not going to change. We can, however, seek reason behind it (or at least attempt to).
If you know the true reasons behind the decision, please share!
No troubles here, both foo and bar are of type int*. intptr is an alias for int*, int* is a complete type. So why can't I replace it with int*?
My rule of thumb is to never typedef a pointer. Not only does it avoid having to answer that question at all, it avoids some nasty bugs. But feel free to show me a real world situation where such a typedef is more good than evil...
.oisyn
06-28-2007, 04:19 PM
True. But does it matter? My point is that complaining about the syntax doesn't help.
Well, it creates awareness. That's important :).
It's not going to change. We can, however, seek reason behind it (or at least attempt to).
If it's not going to change (which it indeed isn't for C++, but it is for other derived languages - C# has * as part of it's type, and both C# and Java use [] in a similar way), then seeking reasons is just as helpless as complaining - we just have to make due with the way it is :)
If you know the true reasons behind the decision, please share!
No I don't either, sorry.
My rule of thumb is to never typedef a pointer. Not only does it avoid having to answer that question at all, it avoids some nasty bugs. Which is completely beyond the scope of this discussion :)
flux00
06-28-2007, 08:18 PM
Seriously, does anyone have a recommendation for a good compiler? MinGW seems to like to warn me about divide-by-zeros and int literals exceeding the signed type, but not
Spectrum operator * (float f) const
{
Spectrum r(0.F);
for (unsigned int i=0; i<SAMPLES; ++i)
{
r.x[i] = x[i] * f;
}
}
Reedbeta
06-28-2007, 08:43 PM
Visual Studio. Seriously, it has a good compiler, not to mention arguably the best IDE and debugger in the C++ world.
Although MinGW should give you that warning. Did you have any luck with -Wall?
flux00
06-28-2007, 09:14 PM
Oh wow, yeah I had it on the wrong line of the makefile, why wouldn't this give a compile-time error though?
Do you have to use the visual studio ide with the compiler?
t0rakka
06-28-2007, 11:02 PM
Nick, pointer-to-function springs to mind as convenient typedef now and then. :D
hunguptodry
06-29-2007, 01:31 AM
int *p;
1) seems quite natural to me.
2) *p is an int and therefor p is a pointer to an int.
Well, it creates awareness. That's important :).
If it's not going to change (...), then seeking reasons is just as helpless as complaining - we just have to make due with the way it is :)
Creating awareness is important. Going round in circles isn't though... So seeking reasons, and finding some, is in my opinion not as helpless as to keep complaining about the syntax.
Nick, pointer-to-function springs to mind as convenient typedef now and then.
Good one. After giving it some thought, it does behave according to an acceptable rule. The * is inside the typedef, so we can't see which variables are decorated and which are not. Hence, all declared variables in a comma delimited list have to be of the same type. Also have a look at this:
int a, *b;
funcptr f, *g;
The first line creates integers. The second variable, *b, allows to access the address by removing the * decoration. So b itself is a pointer to an integer. The second line creates function pointers. The second variable, *g, allows to access the address by removing the * decoration. So g itself is a pointer to a function pointer.
No ambiguity according to this rule here. Just write * next to the variable name (or, decorate the pointer name with it) and not the type, and it makes it easier to interpret these things correctly.
Reedbeta
06-29-2007, 09:13 AM
Oh wow, yeah I had it on the wrong line of the makefile, why wouldn't this give a compile-time error though?
Do you have to use the visual studio ide with the compiler?
I'm not sure why it wouldn't give an error...there's probably some historical C reason why that's legal. Anyway, you can use the VS compiler from the command line if you want, though I honestly don't know why you would.
We seem to have gotten off topic, though, so if you'd like to continue this conversation I suggest PMing me. :)
.oisyn
07-01-2007, 06:18 AM
Good one. After giving it some thought, it does behave according to an acceptable rule. The * is inside the typedef, so we can't see which variables are decorated and which are not. Hence, all declared variables in a comma delimited list have to be of the same type. Also have a look at this:
int a, *b;
funcptr f, *g;
The first line creates integers. The second variable, *b, allows to access the address by removing the * decoration. So b itself is a pointer to an integer. The second line creates function pointers. The second variable, *g, allows to access the address by removing the * decoration. So g itself is a pointer to a function pointer.
No ambiguity according to this rule here. Just write * next to the variable name (or, decorate the pointer name with it) and not the type, and it makes it easier to interpret these things correctly.
Function pointers are not that different than normal pointers. In fact, in your example you define the pointer as part of the type, while you don't want to do that for value types. Why is that?
typedef void myfunc();
myfunc a, *b;
Here, a is a function declaration, b is a pointer-to-function definition. If you want to call a, you write a(). If you want to call b, you *could* write (*b)(). However, for pointer-to-functions, it is allowed to omit the dereference, so you can also write b(). Then again, if you want to bind it to a reference, you'll have to do *b anyway.
And just as with normal types, you can create pointer-to-members with these functiondefinitions as well :)
int a, *b, MyClass::*c;
myfunc f, *g, MyClass::*h;
So, function types are not at all different from regular types :)
vBulletin, Copyright ©2000-2010, Jelsoft Enterprises Ltd.