|
Yeah I've coded in C and C++ for a long time, to the point where it doesn't confuse me. I just don't like the inconsistency. I understand why it is from a syntax perspective.
In c#
int[] array = new int[10];
But in C it doesn't make sense to use new, and int[10] array; is ugly.
Still, it just bugs me, because they're both type modifiers.
Real programmers use butterflies
|
|
|
|
|
You are thinking about it the wrong way, I believe.
There is an implicit Algebra: * = 1/&
so, char *p, LITERALLY says (*p) is a char.
therefore &(*p) => Address of that char!
but knowing the algebra & and * cancel each other out (as do & and [)
So, p is a pointer to a specific char. And the beauty of this, is that how you declare it usually implies how you are going to use it. A fixed array is declared as char a[10]; Which again, says (to me), I want an array of 10 characters, a POINTS to the first character, and a[1] == *(a+1).
I always found this part of C very expressive and self-explanatory.
Of course, I learned PDP/11 Macro-11 Assembly BEFORE I learned C. So most of this was mapping to register level access of R0 vs (R0) [Memory direct and indirect addressing].
Mov 65, R0 ; Stores the value in the register
Mov 65, (R0) ; Stores 65 at the memory location of R0
Mov 65, (R0++) ; Stores 65 at the memory location and increments the memory location AFTER to the next
; Note its been 35 years, the syntax is illustrative of the features.
If you know how the variable is declared, you should instantly understand the various ways you can dereference it.
|
|
|
|
|
We seem to be talking about two different things.
I'm simply talking about type modifiers and how they are applied to types. In C the pointer modifier comes after the type, and the array modifier comes after the variable or member declaration. It's just a slight syntactic (purely cosmetic) inconsistency that has irked me for the years that I've used C and C++.
Real programmers use butterflies
|
|
|
|
|
Okay, I apologize.
Now, consider this, how do I declare 3-5 arrays of different sizes?
char a[2],b[5],c[6],d[7];
char [2]a, ...
char[2] a;
char[5] b;
char...
also, neat trick, 2[c] == c[2];
// because ANSI declared n[c] == *(c+n), and therefore c[n] == *(n+c)
I think I would be confused if it was any other way than it is now.
The cool thing is you could use the preprocessor to make it work like you want (and be threatened by every living programmer for HORRIBLE form, LOL). [I used to use the preprocessor... A Lot... LOL]
|
|
|
|
|
wait, are you declaring char [2]a backward to illustrate a point?
just to be clear literally I'd ask for is a single change from this:
char sz[100];
To this
char[] sz[100];
Even if it requires extra typing it would be more consistent.
Everything else would be the same.
And I'd never abuse the preprocessor that way with the exception of using it to help code complicated compile time computations and make writing them easier. Like the Spirit parsing framework.
Real programmers use butterflies
|
|
|
|
|
Ah,
therein lies the dilemma:
What does
char[] a[100], b;
declare b as?
Worse, when I read "a", it says: "a[100]" is an ELEMENT (or pointer) to an array,
Because I see it as:
char []a[100];
char *a[100];
and
char[] a(100);
The * modifier and the [] modifiers are applied to the variable, not the type.
hence
char *a,**b,c[100],d;
// And yes the [2]a was just "putting it in front, as requested"
But I feel we must "adapt" to nuances of every language. I primarily code in Delphi (Pascal based) for the last 20+ years... So I am having to THINK HARDER about C and C# syntax.
That adaptation in C is pretty low, and coding standards would say the Decoration stays with the variable, not the type! That rectifies about 80% of it to me.
Proof:
char* a,b,c;
char *a,b,c;
IMO...
|
|
|
|
|
You make a good point. At which my response is I don't like that C puts the type modifiers with the variable in general.
C# doesn't, and i appreciate it for that, but I guess I've been spoiled as this last year i was doing mostly C# stuff.
Real programmers use butterflies
|
|
|
|
|
As I understand it declarations are written as if operators e.g. you would write "name[123]" to access the 123'rd element in the array named "name" so that's how it is declared. Maybe it should be "[123]name".
|
|
|
|
|
You seem to be talking about accessing the array, not declaring it. I'm talking about declaring it.
Edit: Or if you are, then I think get your point? My response would be that pointers aren't declared like pointer operations.
Real programmers use butterflies
|
|
|
|
|
They aren't? I would declare a pointer using the rules of operator precedence always starting with the identifier e.g. "char* name" and utilize it as an operator as "*name" so except for the white space and the casting operator "char" which is no longer needed they are the same. Cheerios
|
|
|
|
|
I think we're misunderstanding each other. My OP maybe wasn't as clear as it should have been.
I've always declared pointers with the * next to the type. You CANNOT declare arrays that way. Hence my complaint.
Real programmers use butterflies
|
|
|
|
|
Greetings My point is that if you accept the rules of operator precedence and associativity which I am assuming you do than you must accept the rules of declaration since they are identical. Otherwise you must argue against both and insist e.g. that array elements be referenced as "[123]name" or pointer targets as "name*". Or perhaps you would argue that the rules of declaration be different from the rules of operation but that would complicate things. Kind Regards Cheerios
|
|
|
|
|
Oh, I get you. I guess using operator precedence on type modifiers kind of threw me, but i can see why you look at it that way.
Real programmers use butterflies
|
|
|
|
|
Greetings and Kind Regards Just in passing I wish to mention in case you do not already know about it is that the C text by Harbison & Steele is what the K&R text wished it was. H&S is a beautiful text and is where I learned that declarations and operations follow the same rules. Why K&R didn't explain this is as simply is difficult to understand. Best Wishes Cheerios
|
|
|
|
|
You could use 123[name] as an alternative - that matches the original PDP addressing mode syntax better as well, I suspect!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
|
|
|
|
|
honey the codewitch wrote: I think it's inconsistent, and I think the array specifier should have been declared with the type since it's essentially a type modifier like * and &
One thing it's not is inconsistent - the pointer modifier belongs with the variable, not the type. For example, the following fragment declares a pointer to integer variable and an integer variable.
int *pa, a;
See this Godbolt...
One option, were you using C++...
template<class T, size_t N>
using Array = T[N];
template<class T>
using Ptr = T*;
Array<int, 10> test_array;
Ptr<int> test_pointer;
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
|
|
|
|
|
Stuart Dootson wrote: One thing it's not is inconsistent - the pointer modifier belongs with the variable, not the type.
Yet it's a type modifier. A pointer to an int is a different type than an int.
Real programmers use butterflies
|
|
|
|
|
Quote: Does it bother anyone else that you declare a pointer like:
char* sz;
It only looks odd if you use it like that. If you use it like the way it was meant to be used:
char *sz;
It makes sense. The way you write it is not consistent and lends itself to errors.
char* szA, szB, szC;
char *szD, *szE, *szF;
Putting the "*" next to the typename is logically inconsistent - you still have to put the "*" in the correct place for other pointer types:
void (*fptr) (void);
So instead of doing it one way for some variables and the correct way for others, just do it the correct way for all.
|
|
|
|
|
I suppose then that I do not like that type modifiers are not declared with the type.
Real programmers use butterflies
|
|
|
|
|
Quote: I suppose then that I do not like that type modifiers are not declared with the type.
Pointers aren't type modifiers.
You can tell by the way that actual type modifiers can be placed in any order ("short int" and "int short") while the pointer notation can only go before the variable name.
short int si1;
int short si2;
short int *psi3;
*short int psi4;
If you do not associate the '*' with the variable name, then everything looks very confusing and arbitrary and some things that should work won't. If you associate the '*' with the variable name then everything is logical and can be worked out - any "*symbol" means that symbol is a pointer to something, so things like this can be worked out:
const char *varname[100];
You cannot logically infer what that means if you think that the "*" is part of the typename. If the "*" is part of the type, that would mean that the pointer can not be changed. In reality, it is the individual chars that cannot be changed, while each of the pointers in the array can be changed.
There's a lot of misunderstanding that will happen when "typename* varname" is used in place of "typename *varname". A compiler won't catch all of it.
|
|
|
|
|
It bothers me to no end. Actually what bothers me even more is that every time I mention it, I mostly get replies defending the stupid Spiral of Death. It's bad enough that it's bad, but worse that people feel this kind of Stockholm Syndrome towards a type syntax that just doesn't make sense. (in some sense it's not even a type syntax, because it's not just a type, there's a declaration stuck in the middle of it)
Anyway I'll show you something even worse, the syntax for returning a function pointer. Let's say you want to return a pointer to a function that takes two ints and returns an int, a function like int add(int a, int b) maybe. It would look like this:
int (*getFunc())(int, int) { … }
Unless you use a typedef of course (in C# that is essentially mandatory: you must declare a delegate with the signature first and then you can use that).
|
|
|
|
|
harold aptroot wrote: but worse that people feel this kind of Stockholm Syndrome towards a type syntax that just doesn't make sense
I think you're the first person on this thread to agree with me.
Real programmers use butterflies
|
|
|
|
|
Greetings but I must differ
int foobar(int, int) { return 0; }
// I merely followed the operator rules of precedence and associativity for:
// "f is a pointer to a function which takes two arguments of type int and int and returns an int"
// and voila though the return type doesn't seem to be an operator unless perhaps a cast operator
int (*f)(int, int) = foobar; // compiles ok
int (*getFunc())(int, int) = foobar; // compiles with syntax error
// Cheerios
|
|
|
|
|
But that's not what I wrote. I wanted to return a function pointer from a function named getFunc .
|
|
|
|
|
Greetings and Kind Regards Please permit me to demonstrate the following: By merely following the rules of operator precedence and associativity I deduce the same declaration for getFunc as yourself. I thank Harbison & Steele for teaching me this in their fine C text. Why K&R don't do this is difficult to understand.
// "getFunc is a function which returns a pointer to a function which takes two int args and returns an int"
// getFunc is a function ...
getFunc()
// ... which returns a pointer ...
*getFunc()
// ... to a function which takes two int args ...
*getFunc()(int, int)
(*getFunc())(int, int) // added ()'s because function call (int, int) has higher precedence than indirection *
// ... and returns an int
int (*getFunc())(int, int)
// Voila No Spiral of Death is needed. Best Wishes Cheerios
|
|
|
|