By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,316 Members | 2,132 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,316 IT Pros & Developers. It's quick & easy.

gcc: pointer to array

P: n/a
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe
Nov 15 '05 #1
Share this Question
Share on Google+
204 Replies


P: n/a
Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.

So, you pass int* to print2, and it expects an array of int* - i.e. int**.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com

"Alexei A. Frounze" <al*****@chat.ru> wrote in message
news:3j************@individual.net...
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe

Nov 15 '05 #2

P: n/a
"Maxim S. Shatskih" <ma***@storagecraft.com> wrote in message
news:da***********@gavrilo.mtu.ru...
Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.
It's not. :) The values are identical, but the types aren't, strictly
speaking. If you pass &aInt2 to print1(), you'll have a problem. You won't,
if you pass aInt2 or &aInt2[0]. This is clear. And it's not the problem.
So, you pass int* to print2, and it expects an array of int* - i.e. int**.

int (*p)[5] declares p as a pointer to array of 5 elements of type int. It's
not an array of 5 pointers, nor a pointer to such array!

Alex
--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com

"Alexei A. Frounze" <al*****@chat.ru> wrote in message
news:3j************@individual.net...
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type
Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe


Nov 15 '05 #3

P: n/a
Alexei A. Frounze wrote:

void print2 (const int (*p)[5])


arg1 of print2 seems a pointer to a function... isn't it?
--
daniele_athome
Nov 15 '05 #4

P: n/a
"daniele_athome" <da******************@fastwebnet.it> wrote in message
news:tw******************@tornado.fastwebnet.it...
Alexei A. Frounze wrote:

void print2 (const int (*p)[5])


arg1 of print2 seems a pointer to a function... isn't it?


It looks very similar, but it's not :) The [] brackets tell the array, not
function, for which they should've been (), like so:
int (*p)(/*argument(s)*/)

Alex
Nov 15 '05 #5

P: n/a
daniele_athome wrote:
Alexei A. Frounze wrote:
void print2 (const int (*p)[5])

arg1 of print2 seems a pointer to a function... isn't it?


No. p is a pointer to array 5 of const int. Alexei gets this wrong too.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #6

P: n/a
"Joe Wright" <jo********@comcast.net> wrote in message
news:0u********************@comcast.com...
daniele_athome wrote:
Alexei A. Frounze wrote:
void print2 (const int (*p)[5])

arg1 of print2 seems a pointer to a function... isn't it?


No. p is a pointer to array 5 of const int. Alexei gets this wrong too.


Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex
Nov 15 '05 #7

P: n/a
"Alexei A. Frounze" <al*****@chat.ru> wrote in message
news:3j************@individual.net...
"Joe Wright" <jo********@comcast.net> wrote in message
news:0u********************@comcast.com...
daniele_athome wrote:
Alexei A. Frounze wrote:

>void print2 (const int (*p)[5])
arg1 of print2 seems a pointer to a function... isn't it?


No. p is a pointer to array 5 of const int. Alexei gets this wrong too.


Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex


To clarify further, "... and ensure that *the array (not the pointer)* it's
not modified in anyway inside print2()."
Alex
Nov 15 '05 #8

P: n/a

print2 expects pointer to constant array so
how about declaring aInt3 to constant or modify print2 parameter list...
- jt


Alexei A. Frounze wrote:
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe

Nov 15 '05 #9

P: n/a
Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?

Alex

"Tommi Johnsson" <TE*@Merlin.Mirrorland> wrote in message
news:dM*****************@reader1.news.jippii.net.. .

print2 expects pointer to constant array so
how about declaring aInt3 to constant or modify print2 parameter list...
- jt


Alexei A. Frounze wrote:
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type
Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2(). However the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe

Nov 15 '05 #10

P: n/a


Alexei A. Frounze wrote:

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};
void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type

Why is that?


Try removing the const keyword.
Example:

#include <stdio.h>

void print2 (int (*p)[5])
{
size_t i;

for(i = 0; i < 5; i++)
printf ("%d\n", (*p)[i]);
return;
}

int main(void)
{
int p[5] = {1,2,3,4,5};
print2(&p);
return 0;
}
--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 15 '05 #11

P: n/a
"Al Bowers" <ab*****@myrapidsys.com> wrote in message
news:3j************@individual.net...
....
Try removing the const keyword.

....

But I want to keep it. :)

Alex
Nov 15 '05 #12

P: n/a
Alexei A. Frounze wrote:
"Alexei A. Frounze" <al*****@chat.ru> wrote in message
news:3j************@individual.net...
"Joe Wright" <jo********@comcast.net> wrote in message
news:0u********************@comcast.com...
daniele_athome wrote:

Alexei A. Frounze wrote:
>void print2 (const int (*p)[5])
arg1 of print2 seems a pointer to a function... isn't it?

No. p is a pointer to array 5 of const int. Alexei gets this wrong too.


Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex

To clarify further, "... and ensure that *the array (not the pointer)* it's
not modified in anyway inside print2()."
Alex


Sorry Alex, I jumped on you in error. It would seem to be a 'const'
issue. If I remove the const qualifier from the print2 parameter it
works. Or if I add const to the array definition..

const int aInt3[5] = {0, 1, 2, 4, 9};

it works too. Go figure. I don't have a good handle on 'const'.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #13

P: n/a
Alexei A. Frounze wrote:
Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?
i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

- jt


"Tommi Johnsson" <TE*@Merlin.Mirrorland> wrote in message
news:dM*****************@reader1.news.jippii.net.. .
print2 expects pointer to constant array so
how about declaring aInt3 to constant or modify print2 parameter list...
- jt


Alexei A. Frounze wrote:
Hi all,

I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt2[6] = {0,1,2,4,9,16};
int aInt3[5] = {0,1,2,4,9};

void print1 (const int* p, size_t cnt)
{
while (cnt--)
printf ("%d\n", *p++);
}

void print2 (const int (*p)[5])
{
size_t cnt;
#if 0
// prohibited:
(*p)[0]=0;
#endif
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
printf ("test begin\n");

print1 (aInt2, sizeof(aInt2)/sizeof(aInt2[0]));
print2 (&aInt3); // <-- warns here

printf ("test end\n");
return 0;
}

The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer
type
Why is that? How is this different from using print1 (aInt2, ...)? All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2().
However
the #if 0'd assignment operator inside print2() is correctly handled by
gcc -- an error is generated:
MOD.c: In function `print2':
MOD.c:: error: assignment of read-only location
What's wrong with gcc?

There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...
Is this OK???

Thanks,
Alex
P.S. I compile it as gcc MOD.c -Wall -oMOD.exe


Nov 15 '05 #14

P: n/a
"Joe Wright" <jo********@comcast.net> wrote in message
news:H7********************@comcast.com...
Alexei A. Frounze wrote:
"Alexei A. Frounze" <al*****@chat.ru> wrote in message
news:3j************@individual.net...
"Joe Wright" <jo********@comcast.net> wrote in message
news:0u********************@comcast.com...

daniele_athome wrote:

>Alexei A. Frounze wrote:
>
>
>>void print2 (const int (*p)[5])
>
>
>arg1 of print2 seems a pointer to a function... isn't it?

No. p is a pointer to array 5 of const int. Alexei gets this wrong too.

Excuse me, but what did I get wrong? Isn't what you're trying to say the
same as in my original post (excerpt): "All I
want to do is to explicitly show that the pointer is to an array of 5
entries and ensure that it's not modified in anyway inside print2()."?

Alex

To clarify further, "... and ensure that *the array (not the pointer)* it's not modified in anyway inside print2()."
Alex


Sorry Alex, I jumped on you in error. It would seem to be a 'const'
issue. If I remove the const qualifier from the print2 parameter it
works. Or if I add const to the array definition..

const int aInt3[5] = {0, 1, 2, 4, 9};

it works too. Go figure. I don't have a good handle on 'const'.


That's what I'm trying to find explanation for. I mean, not the const,
rather the odd warning.
Anyway, const prohibits modification of data. Putting it in different
positions near * results in treatment of different object as
constant/unalterable. For instance:

int *p - modifiable pointer to modifiable int
const int *p - modifiable pointer to constant int
int* const p = initvalue; - constant pointer to modifiable int
const int* const p = initvalue; - constant pointer to constant int

int** pp - modifiable pointer to modifiable pointer to modifiable int
const int** pp - modifiable pointer to modifiable pointer to constant int
int* const* pp - modifiable pointer to constant pointer to modifiable int
int** const pp = initvalue; - constant pointer to modifiable pointer to
modifiable int
etc etc...

Maybe I should look into c99 or better ask gcc guys what's going on.
I can also try the thing with other compilers. By now I know that Borland's
old Turbo C/C++ 16-bit compiler for DOS handles the pointer to const array
w/o the warning. There're other Borland's, Open Watcom and VC++ to try...
Though, VC++ is known to emit even more stupid warnings (like a=b=0; where a
and b are for e.g. short and int, and 0 says nothing to the compiler).

Best regards,
Alex
Nov 15 '05 #15

P: n/a
"Tommi Johnsson" <TE*@Merlin.Mirrorland> wrote in message
news:4L****************@reader1.news.jippii.net...
Alexei A. Frounze wrote:
Yes, this would work fine if aInt3[] were declared as const array... But the problem is that the compiler allows pointers to consts to non-const data but warns on pointers to const array to non-const data. That's why I presented both things in the test program. Kinda odd, don't you think so? I mean, I can put there a type cast to get rid of the warning, but this warning in its very core is stupid. Why "const int*" should be better than or in any other way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any idea?


i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

- jt


There were no "const int **p" in the code. Besides, "const int **p" declares
a modifiable pointer to a modifiable pointer to a constant int. There's no
double indirection anywhere in the code.

Anyway, can you suggest a declaration of the function's argument that would
simultaneously satisfy:
- being a pointer to an array of a fixed number of elements, say, 5 integers
- this array is to be constant, in other words, its elements can't be
altered by using the pointer

Can it be declared like that provided the compiler does not emit any warning
if as argument I use an array (its address) that isn't constant?

Why can I do it with one value, e.g. pass a pointer to modifiable int or
modifiable array of ints to a function whose argument is of type "const
int*", but I can not do the same with an array of fixed number of ints?

Alex
Nov 15 '05 #16

P: n/a


Alexei A. Frounze wrote:
"Al Bowers" <ab*****@myrapidsys.com> wrote in message
news:3j************@individual.net...
...
Try removing the const keyword.


...

But I want to keep it. :)


If castration of const is out, do not pout.
Casting, a pollution, is one solution.

(const int (*)[5])

--
Al Bowers
Tampa, Fl USA
mailto: xab*****@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 15 '05 #17

P: n/a
"Al Bowers" <ab*****@myrapidsys.com> wrote in message
news:3j************@individual.net...


Alexei A. Frounze wrote:
"Al Bowers" <ab*****@myrapidsys.com> wrote in message
news:3j************@individual.net...
...
Try removing the const keyword.
...

But I want to keep it. :)


If castration of const is out, do not pout.
Casting, a pollution, is one solution.

Very smart :)
(const int (*)[5])


This is even smarter. :)

So, I presume nobody knows what's wrong. I haven't found anything on this
particular thing in C99. Maybe it's just gcc's way to do things... I need
more statistics.
Alex
Nov 15 '05 #18

P: n/a
On Sun, 10 Jul 2005 19:48:00 +0400, "Maxim S. Shatskih"
<ma***@storagecraft.com> wrote:
Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.
The original post defined an array as int aInt3[5]. Ignoring your
typo in the name:

&aInt3 has type pointer to array of 5 int.

aInt3 in most contexts, including the question raised in the
original post, will be converted to the address of the first element
with type pointer to element type. In this case, it is pointer to
int.

The two types are not compatible.

So, you pass int* to print2, and it expects an array of int* - i.e. int**.


The original post passed &aInt3 to print2, so it did not pass an int*.
print2 was defined in the original post as
void print2 (const int (*p)[5])

The argument is declared as type pointer to constant array of 5 int,
not as an array of pointer to int. While an array of int* would be
passed to a function as an int**, the two are not synonymous at all.
<<Remove the del for email>>
Nov 15 '05 #19

P: n/a
On Mon, 11 Jul 2005 00:53:27 +0400, Alexei A. Frounze wrote:
"Tommi Johnsson" <TE*@Merlin.Mirrorland> wrote in message
news:4L****************@reader1.news.jippii.net...
Alexei A. Frounze wrote:
> Yes, this would work fine if aInt3[] were declared as const array...
> But the > problem is that the compiler allows pointers to consts to non-const
> data but > warns on pointers to const array to non-const data. That's why I presented > both things in the test program. Kinda odd, don't you think so? I
> mean, I > can put there a type cast to get rid of the warning, but this warning
> in its > very core is stupid. Why "const int*" should be better than or in any other > way differ from "const (*int)[]"? Where's the rationale? I don't see
> it. Any > idea?

Yes, see below.

i think, it's because types differs from each other... in print1 you
declare `p` as an pointer to const qualified int. -->> pointed value is
const qualified and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

Yes, the double indirection is the cause of the warning.
There were no "const int **p" in the code.
I don't think jt was saying there was. He was saying that you should be
comparing print2 function's parameter with "const int **p" rather than
with print1's "const int *p" as you have been doing. This is the source
of your confusion.
Besides, "const int **p"
declares a modifiable pointer to a modifiable pointer to a constant int.
There's no double indirection anywhere in the code.
A pointer to an array *is* double indirection. So print2's first
parameter is doubly indirected.
Anyway, can you suggest a declaration of the function's argument that
would simultaneously satisfy:
- being a pointer to an array of a fixed number of elements, say, 5
integers - this array is to be constant, in other words, its elements
can't be altered by using the pointer
No. To the best of my understanding it is not possible according to the
standard.
Can it be declared like that
Like what?
provided the compiler does not emit any
warning if as argument I use an array (its address) that isn't constant?

Why can I do it with one value, e.g. pass a pointer to modifiable int or
modifiable array of ints to a function whose argument is of type "const
int*", but I can not do the same with an array of fixed number of ints?


This question was answered recently in another thread. See
message id <87************@hardknott.home.whinlatter.ukfsn.or g>
dated Wed, 6 Jul 2005 22:54:41 +0000 (UTC)
on comp.lang.c
subject Implicit addition of const qualifiers

Hint, try adding a function:

void print3 (const int** p, size_t cnt) {
while (cnt--)
printf ("%d\n", *(*p)++);
}

and in your main code:
int *pInt = aInt2;
print3 (&pInt, sizeof(aInt2)/sizeof(aInt2[0]));

You'll get the same warning.

The problem is the double indirection - the standard won't allow the
non-const to be automatically converted to const in such cases.

Wouldn't you know it - you'll have to go with the poet. A cast is
required.

Nov 15 '05 #20

P: n/a
On Mon, 11 Jul 2005 01:39:21 +0400, Alexei A. Frounze wrote:
"Al Bowers" <ab*****@myrapidsys.com> wrote in message
news:3j************@individual.net...


Alexei A. Frounze wrote:
> "Al Bowers" <ab*****@myrapidsys.com> wrote in message
> news:3j************@individual.net... ...
>
>>Try removing the const keyword.
>
> ...
>
> But I want to keep it. :)
>
> If castration of const is out, do not pout. Casting, a pollution, is one
solution.

Very smart :)
(const int (*)[5])


This is even smarter. :)

So, I presume nobody knows what's wrong.


Well it's strange that you haven't had a more direct explanation as to
why the problem is occurring as yet.
I haven't found anything on this
particular thing in C99.
I'm not sure if it's in C90 or C99... I haven't looked myself but see the
thread I refer to in my other post which mentions it as being in standard
C++.
Maybe it's just gcc's way to do things... I need more statistics.


I haven't consulted the standards and don't know whether gcc is complying
with C90 or C99. But intuitively it is correct behaviour - double
indirection can easily be used to gain access to the supposedly protected
const type by assigning the middle pointer to a non-const pointer.
There's no way the compiler can detect this, so disallowing automatic
const-conversion for double-indirection parameters makes sense.

Nov 15 '05 #21

P: n/a
On Mon, 11 Jul 2005 09:22:08 +1000, Netocrat wrote:
Anyway, can you suggest a declaration of the function's argument that
would simultaneously satisfy:
- being a pointer to an array of a fixed number of elements, say, 5
integers - this array is to be constant, in other words, its elements
can't be altered by using the pointer


No. To the best of my understanding it is not possible according to the
standard.


Disclaimer: my knowledge of the standard is very patchy and I made this
statement based on the thread that I referenced - but looking at it again
I see that there is no actual mention of C90 or C99 - just C++ standards.
So I really don't know what the standard says about this and I'm not
motivated to go hunting through the drafts to find out. You say you've
looked and can't find anything: perhaps one of the standards gurus of this
group can clarify. It is intuitively correct behaviour though whether
standards-specified or not.

Nov 15 '05 #22

P: n/a
Alexei A. Frounze wrote:
I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt3[5] = {0,1,2,4,9};

void print2 (const int (*p)[5])
{
}

int main()
{
print2 (&aInt3); // <-- warns here
return 0;
} The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type
The compiler is correct. The pointers point to incompatible types;
the element type of one array is const-qualified, and it isn't in the
other. Type compatibility is recursive, and types with different
qualifiers are not compatible.

Either the function needs to lose the const qualifier, or you need to
add it to your array.
There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.
That's hard as it has to follow what your program is doing, not just
the syntax. It's certainly possible to warn, though; some lint
programs would.
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...


That's easy to warn about and GCC should do it. I suggest you file an
enhancement request.

Nov 15 '05 #23

P: n/a
Alexei A. Frounze wrote:

I have a question regarding the gcc behavior (gcc version 3.3.4).
You got an unusually high number of garbage responses :)
On the following test program it emits a warning:
#include <stdio.h>

int aInt3[5] = {0,1,2,4,9};

void print2 (const int (*p)[5])
{
size_t cnt;
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
print2 (&aInt3); // <-- warns here
return 0;
}

MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type


print2 is expecting a pointer to an array of constant ints.

Note, you can't have a "const array" in C -- you can
only have an array whose members are all const.

aInt3 is an array of ints, and there is no implicit conversion
in C from pointer-to-array-of-T to pointer-to-array-of-const-T
(or an array of anything else, for that matter). This could be
considered a language defect.

But, this does work:
typedef int (*P5INT)[5];
void print2(const P5INT p)
{

AFAIK it's not possible to do this without a typedef.

Nov 15 '05 #24

P: n/a
On Sun, 10 Jul 2005 18:01:17 -0700, Old Wolf wrote:
[T]here is no implicit conversion in C from pointer-to-array-of-T to
pointer-to-array-of-const-T (or an array of anything else, for that
matter). This could be considered a language defect.
In this case it certainly would be useful. I don't see how any harm could
be done.
But, this does work:
typedef int (*P5INT)[5];
void print2(const P5INT p)
{
Not as the OP intended though. It is an equivalent prototype to:
void print2(int (*const p)[5])

So it does allow the function to be called as the OP desired - ie with a
non-const array - and without a cast - but it also removes the desired
const protection... you can now assign to (*p)[0] within the function.
The semantics of your parameter are to make p itself const, rather than
what it points to. i.e. if you add to the function:

int pp[5];
p = &pp;

you will get a warning about attempting to write to a read-only location.
AFAIK it's not possible to do this without a typedef.


It is though, as per above.

Nov 15 '05 #25

P: n/a
On Mon, 11 Jul 2005 09:29:27 +1000, Netocrat wrote:
[D]ouble indirection can easily be used to gain access to the supposedly
protected const type by assigning the middle pointer to a non-const
pointer. There's no way the compiler can detect this, so disallowing
automatic const-conversion for double-indirection parameters makes sense.


I'm talking nonsense. You can't assign the middle pointer to a non-const
pointer without a cast. But you can use the automatic conversion to
violate the const protection: quoting "Me" in another thread:

const char c = 'c';
char * pc;
const char ** pcc = & pc ; /* not allowed */
*pcc = & c;
*pc = 'C'; /* would modify a const object if the conversion above were
* allowed */

Nov 15 '05 #26

P: n/a
On Mon, 11 Jul 2005 12:38:37 +1000, Netocrat wrote:
On Sun, 10 Jul 2005 18:01:17 -0700, Old Wolf wrote:
[T]here is no implicit conversion in C from pointer-to-array-of-T to
pointer-to-array-of-const-T (or an array of anything else, for that
matter). This could be considered a language defect.


In this case it certainly would be useful. I don't see how any harm could
be done.


OK I take that back after reading another thread - harm could be done.
It's definitely not a defect but a required safety mechanism.

Nov 15 '05 #27

P: n/a
> A pointer to an array *is* double indirection.

No. It is absolutely the same as the pointer to its first element.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #28

P: n/a
On Mon, 11 Jul 2005 14:01:57 +0400, Maxim S. Shatskih wrote:
A pointer to an array *is* double indirection.
No.


An array is one layer of indirection. Given its similarity to a pointer I
don't see much controversy in that statement. A pointer to an array is
therefore a second layer of indirection. What do you find disagreeable
about this reasoning?
It is absolutely the same as the pointer to its first element.


What is "the pointer" to which you are referring? Do you mean the
address of its first element? In that case your statement is plainly
absurd - a pointer to an array is much more than just an address. So I
doubt that you mean that. Generally a pointer is a variable... but
we've only got one variable here, and you can't be claiming equivalence
with itself since that is true but meaningless. So what _do_ you mean?

Your statement is also vague because "first element" could be applied to
the array pointer or to the array that it points to. You don't make it
clear which you mean. i.e. given:

int (*ap)[5] = &a;

it is possible to access "it's first element" as ap[0] or (*ap)[0].

Although your statement is vague, I interpret it to be saying that

ap == &(*ap)[0]

which I don't disagree with. Since you are disagreeing with my double
indirection statement though, you perhaps would also be arguing that

ap[0] == (*ap)[0]

That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which can
be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it is
an access of the second "5 element integer array" element of ap. We can
make it valid by doing this:
ap = malloc(sizeof(a) * 10);
if (!ap) abort_no_mem();

Now we can write things like ap[7][4] which accesses the 5th (and last)
element of the 8th "5 element integer array" in the array of "5 element
integer arrays" which, given our ability to index a pointer as an array,
we can consider ap as representing.

Again demonstrating that a pointer to an array has two layers of
indirection. In any case I found your statement unclear so I have made
a few assumptions but I may have missed your point.

Nov 15 '05 #29

P: n/a
On Mon, 11 Jul 2005 21:06:45 +1000, Netocrat wrote:
On Mon, 11 Jul 2005 14:01:57 +0400, Maxim S. Shatskih wrote:
A pointer to an array *is* double indirection.
No.


An array is one layer of indirection. Given its similarity to a pointer I
don't see much controversy in that statement. A pointer to an array is
therefore a second layer of indirection. What do you find disagreeable
about this reasoning?
It is absolutely the same as the pointer to its first element.


What is "the pointer" to which you are referring? Do you mean the address
of its first element? In that case your statement is plainly absurd - a
pointer to an array is much more than just an address. So I doubt that
you mean that. Generally a pointer is a variable... but we've only got
one variable here, and you can't be claiming equivalence with itself since
that is true but meaningless. So what _do_ you mean?

Your statement is also vague because "first element" could be applied to
the array pointer or to the array that it points to. You don't make it
clear which you mean. i.e. given:


I left this out:

int a[5];
int (*ap)[5] = &a;

it is possible to access "it's first element" as ap[0] or (*ap)[0].

Although your statement is vague, I interpret it to be saying that

ap == &(*ap)[0]

which I don't disagree with. Since you are disagreeing with my double
indirection statement though, you perhaps would also be arguing that

ap[0] == (*ap)[0]

That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which can
be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it is
an access of the second "5 element integer array" element of ap. We can
make it valid by doing this:
ap = malloc(sizeof(a) * 10);
if (!ap) abort_no_mem();

Now we can write things like ap[7][4] which accesses the 5th (and last)
element of the 8th "5 element integer array" in the array of "5 element
integer arrays" which, given our ability to index a pointer as an array,
we can consider ap as representing.

Again demonstrating that a pointer to an array has two layers of
indirection. In any case I found your statement unclear so I have made a
few assumptions but I may have missed your point.


Nov 15 '05 #30

P: n/a
On Sun, 10 Jul 2005 19:51:22 +0400, Alexei A. Frounze wrote:
"Maxim S. Shatskih" <ma***@storagecraft.com> wrote in message
news:da***********@gavrilo.mtu.ru...
Surely.

"&alnt3" is the same as "alnt3", since alnt3 is an array.


It's not. :) The values are identical, but the types aren't, strictly
speaking.


Everything else you've said is spot on, but this is slightly incorrect.
You are right that the values are identical when the array is not a
function parameter. i.e.

#include <stdio.h>
int glob_array[5];

int main(void)
{
int fn_array[5];

if ((&glob_array != glob_array) || (&fn_array != fn_array))
printf("I haven't seen a situation like this before.\n");
}

I don't know however, whether this is mandated by the standard - in
theory it isn't necessary for it to be true, but in practice it would
waste space for it not to be.

However in the context of a function parameter, it is not true. Given
that in C parameters are passed by value, it's not possible for the
address of the array parameter to equal the address of the original array
and therefore it's not possible for the address of the array parameter to
equal the address of the first element that it points to. i.e. we can
write:

#include <stdio.h>
void somefunction(int arrayparm[5])
{
if (arrayparm == &arrayparm)
printf("Something impossible has occurred.\n");
}

Nov 15 '05 #31

P: n/a
Alexei A. Frounze wrote:
"Tommi Johnsson" <TE*@Merlin.Mirrorland> wrote in message
news:4L****************@reader1.news.jippii.net...
Alexei A. Frounze wrote:
Yes, this would work fine if aInt3[] were declared as const array... But
the
problem is that the compiler allows pointers to consts to non-const data
but
warns on pointers to const array to non-const data. That's why I
presented
both things in the test program. Kinda odd, don't you think so? I mean,
I
can put there a type cast to get rid of the warning, but this warning in
its
very core is stupid. Why "const int*" should be better than or in any
other
way differ from "const (*int)[]"? Where's the rationale? I don't see it.
Any
idea?
i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

- jt

There were no "const int **p" in the code. Besides, "const int **p" declares
a modifiable pointer to a modifiable pointer to a constant int. There's no
double indirection anywhere in the code.

Anyway, can you suggest a declaration of the function's argument that would
simultaneously satisfy:
- being a pointer to an array of a fixed number of elements, say, 5 integers
- this array is to be constant, in other words, its elements can't be
altered by using the pointer

Can it be declared like that provided the compiler does not emit any warning
if as argument I use an array (its address) that isn't constant?


Try this one...
Array decays to pointer while array is passed to the function...

int aInt[5] = {1,2,3,4,5};

void print (const int p[5]) {
int x = 25;
if (__builtin_types_compatible_p (typeof (p), const int * ))
printf ("trallalalaa...");
printf ("%d %d %d\n", sizeof (p), sizeof (int[5]), sizeof (const
int *));
//*p[0] = 3;
printf ("%d\n", p[0]);
p = &x;
printf ("%d\n", *p);
}

int main()
{
printf ("test begin\n");

print (aInt);

printf ("test end\n");
return 0;
}
- jt

Why can I do it with one value, e.g. pass a pointer to modifiable int or
modifiable array of ints to a function whose argument is of type "const
int*", but I can not do the same with an array of fixed number of ints?

Alex

Nov 15 '05 #32

P: n/a
> An array is one layer of indirection. Given its similarity to a pointer I
don't see much controversy in that statement. A pointer to an array is
therefore a second layer of indirection. What do you find disagreeable
about this reasoning?
The C notion of the array is another. Array is the same as pointer to its first
element (in all operations except sizeof(), and so ( p + a ) offset
operations).
What is "the pointer" to which you are referring?
MyArray and &(MyArray[0]) is the same in all contexts except sizeof().
absurd - a pointer to an array is much more than just an address.
In C and C++, it is the same.
doubt that you mean that. Generally a pointer is a variable...


Pointer is a value. Value != variable.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
ma***@storagecraft.com
http://www.storagecraft.com
Nov 15 '05 #33

P: n/a
On Sun, 10 Jul 2005 23:35:38 +0300, Tommi Johnsson wrote:
Alexei A. Frounze wrote:
Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?

An array of ints is a fundamentally different type of object to a an int.
So a pointer to an array of ints is quite different to a pointer to an
int, because the properties of a pointer depend very much on the type of
thing they point at.
i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.


But this is an important example of where that is not the case. In
const int (*p)[5] p is already a pointer, it cannot "decay" further. This
array -> pointer conversion is only applicable at the top level of a type.
It is important to remmeber that arrays and pointers really are
fundamentally different types, although their operation is naturally
connected.

Lawrence
Nov 15 '05 #34

P: n/a
[Given "int arr[N];" and considering "&arr" vs "&arr[0]")
On Sun, 10 Jul 2005 19:51:22 +0400, Alexei A. Frounze wrote:
It's not. :) The values are identical, but the types aren't, strictly
speaking.

In article <pa****************************@dodo.com.au>,
Netocrat <ne******@dodo.com.au> wrote:Everything else you've said is spot on, but this is slightly incorrect.
Actually, it is completely correct. :-) But it does not tell you
all that much by itself: as I have shown before, the values of
3 and 3.14 are identical too:

int i = 3;
double d = 3.14;

if ((char)i == (char)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");

Obviously they are only "identical" after conversion to a common
type -- in this case "char" -- and the results may (and do) change
if we pick a different common type:

if ((float)i == (float)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");

To compare &arr against &arr[0], we have to convert to a common
type; and as with the int/double arrangement above, this may change
the value(s) in the process:
#include <stdio.h>
int glob_array[5];

int main(void)
{
int fn_array[5];

if ((&glob_array != glob_array) || (&fn_array != fn_array))
printf("I haven't seen a situation like this before.\n");
}
If you actually compile this, you get the required diagnostic,
and in this particular case, two more diagnostics:

% cc -O2 -W -Wall -ansi -pedantic -o t t.c
t.c: In function `main':
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:10: warning: control reaches end of non-void function

(the C standard requires only that "at least one diagnostic" come
out, and does not say whether it is a "warning", or an "error", or
even a "kumquat"). We can fix this by inserting a conversion to
some common type: for instance, we could cast both to "char *".
But introducing a conversion gets us back to that 3==3.14 problem.
I think the real question boils down to whether &arr and &arr[0]
will compare equal under *all* "well-defined" conversions -- which
may even be only those to "char *" and "void *" -- and then I think
the answer is "yes", so that we can in fact say that the converted
values are always identical as long as we do a sensible conversion.

But, onward:
However in the context of a function parameter, it is not true. Given
that in C parameters are passed by value, it's not possible for the
address of the array parameter to equal the address of the original array
and therefore it's not possible for the address of the array parameter to
equal the address of the first element that it points to. i.e. we can
write:

#include <stdio.h>
void somefunction(int arrayparm[5])
{
if (arrayparm == &arrayparm)
printf("Something impossible has occurred.\n");
}


The real problem here is "what you see, well, all of it's a lie"[%].
The variable named "arrayparm" has type "pointer to int", not "array
5 of int". We can expose the lie via various operators:

/* these sizes will differ (unless you get VERY unlucky) */
printf("sizeof (int [5]) = %lu\n", (unsigned long)sizeof (int [5]));
printf("sizeof arrayparm = %lu\n", (unsigned long)sizeof arrayparm);

/* cannot do this with an array */
arrayparm = NULL;

and of course, your own example, once we insert some appropriate
conversions to eliminate the need for a diagnostic (and perhaps no
executable program as a consequence of the diagnostic):

printf("%p != %p, we presume\n", (void *)arrayparm, (void *)&arrayparm);
if ((void *)arrayparm != (void *)&arrayparm)
puts("we presumed correctly");
else
puts("uh oh");

[% "Wine from the Water", from Try Anything Once]
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #35

P: n/a
On 11 Jul 2005 17:35:54 GMT, Chris Torek
<no****@torek.net> wrote:
[Given "int arr[N];" and considering "&arr" vs "&arr[0]")

I think the real question boils down to whether &arr and &arr[0]
will compare equal under *all* "well-defined" conversions -- which
may even be only those to "char *" and "void *" -- and then I think
the answer is "yes", so that we can in fact say that the converted
values are always identical as long as we do a sensible conversion.


Is that actually defined by the standard? I remember that in some
pre-standard C compilers arrays were actually implemented as pointers,
so int arr[5]; would actually expand to the equivalent in
pseudo-assember:

arr: dw &_arr
_arr: dw ?[5]

(The array pointer itself might be declared in a read-only segment.)

Is this sort of expansion actually banned by the standard, or is it
"just not the done thing"?

In those compilers the effect would be the same as happens with "array
parameters", taking &arr would get you the address of the pointer.

Chris C
Nov 15 '05 #36

P: n/a
Alexei A. Frounze wrote:
...
So, I presume nobody knows what's wrong. I haven't found anything on this
particular thing in C99. Maybe it's just gcc's way to do things... I need
more statistics.
...


What's wrong in the original case is perfectly clear here. The warning is a
consequence of C language's const-correctness rules when they are applied to
arrays (and it's been mentioned here already).

Simply speaking, in accordance with C language's const correctness rules, you
can perform an implicit 'T* -> const T*' conversion. Often people assume that,
say, 'int (*)[10] -> const int (*)[10]' conversion also belongs to that category
and should be performed implicitly without any warnings (that's what you
assumed, apparently). Unfortunately, this is not the case. In C language it is
not possible to const-qualify an array type as a whole. Period. Any attempts to
const-qualify an array type will actually const-qualify the type of the array
_elements_ not the array type itself. In other words, there's no situation in C
when the 'T* -> const T*' can be applied to pointers-to-arrays, since the proper
destination type cannot ever exist in C.

Best regards,
Andrey Tarasevich
Nov 15 '05 #37

P: n/a
Lawrence Kirby wrote:
On Sun, 10 Jul 2005 23:35:38 +0300, Tommi Johnsson wrote:

Alexei A. Frounze wrote:
Yes, this would work fine if aInt3[] were declared as const array... But the
problem is that the compiler allows pointers to consts to non-const data but
warns on pointers to const array to non-const data. That's why I presented
both things in the test program. Kinda odd, don't you think so? I mean, I
can put there a type cast to get rid of the warning, but this warning in its
very core is stupid. Why "const int*" should be better than or in any other
way differ from "const (*int)[]"? Where's the rationale? I don't see it. Any
idea?


An array of ints is a fundamentally different type of object to a an int.
So a pointer to an array of ints is quite different to a pointer to an
int, because the properties of a pointer depend very much on the type of
thing they point at.

i think, it's because types differs from each other...
in print1 you declare `p` as an pointer to const qualified int.
-->> pointed value is const qualified
and
in print2 you declare `p` as an pointer to const qualified array of ints
-->> pointed value is array which elements are const qualified.

i see `const int **p` more like `const int (*p)[5]` than `const int *p`
in this case, because array decays to pointer in most cases.

But this is an important example of where that is not the case. In
const int (*p)[5] p is already a pointer, it cannot "decay" further.


in declaration like const int (*p)[5] it declares only type for p it
really doesnt decay anything but above in 1.st and 2.nd declaration of
pointer p, p is needed to indirect before using p pointed value as an
array, in 3.rd declaration there is no need for that and in later use
p pointed array will decay to the pointer when indirected throught it, i
suppose.

- jt

This
array -> pointer conversion is only applicable at the top level of a type.
It is important to remmeber that arrays and pointers really are
fundamentally different types, although their operation is naturally
connected.

Lawrence

Nov 15 '05 #38

P: n/a
Netocrat wrote:
On Sun, 10 Jul 2005 18:01:17 -0700, Old Wolf wrote:
But, this does work:
typedef int (*P5INT)[5];
void print2(const P5INT p)
{


Not as the OP intended though. It is an equivalent prototype to:
void print2(int (*const p)[5])


Ah, you are correct.

Nov 15 '05 #39

P: n/a
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au...
On Mon, 11 Jul 2005 09:29:27 +1000, Netocrat wrote:
[D]ouble indirection can easily be used to gain access to the supposedly
protected const type by assigning the middle pointer to a non-const
pointer. There's no way the compiler can detect this, so disallowing
automatic const-conversion for double-indirection parameters makes
sense.
I'm talking nonsense. You can't assign the middle pointer to a non-const
pointer without a cast. But you can use the automatic conversion to
violate the const protection: quoting "Me" in another thread:

const char c = 'c';
char * pc;
const char ** pcc = & pc ; /* not allowed */
*pcc = & c;
*pc = 'C'; /* would modify a const object if the conversion above were
* allowed */


Correct, but I don't think it's a good example. Simply being able to modify
something by pc and being unable to modify it by ppc is just fine, so is in
the simpler example:
char c = 'A';
char *pc = &c;
const char *pc_ = &c;
*pc = 'B'; // OK
*pc_ = 'B'; // prohibited
This is how most of libc's functions are declared -- their arguments are of
type of a pointer to a constant value.
This is what I'd like to have with the array too.
I'm not really sure why enforcing protection in this simple case above is OK
(i.e. pc=&c;) but not OK in case of using the array as an object to be
passed by reference/pointer.
I'm fine with warnings and errors caused by the improper use of a pointer to
a constant object, e.g. attempt to modify the constant object. That's
perfectly understandable. Why cannot I enforce such a protection by treating
some object (not necessarily one defined as constant) as a constant one --
that's something I don't get, no matter if there's double indirection or
not. I'm puzzled. What else am I missing?

Alex
Nov 15 '05 #40

P: n/a
<ne**@daikokuya.co.uk> wrote in message
news:11**********************@g43g2000cwa.googlegr oups.com...
Alexei A. Frounze wrote:
I have a question regarding the gcc behavior (gcc version 3.3.4).

On the following test program it emits a warning:
#include <stdio.h>

int aInt3[5] = {0,1,2,4,9};

void print2 (const int (*p)[5])
{
}

int main()
{
print2 (&aInt3); // <-- warns here
return 0;
}
The warning is:
MOD.c: In function `main':
MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer type
The compiler is correct. The pointers point to incompatible types;
the element type of one array is const-qualified, and it isn't in the
other. Type compatibility is recursive, and types with different
qualifiers are not compatible.

Either the function needs to lose the const qualifier, or you need to
add it to your array.
There's another thing about the pointer to the array is... The compiler
doesn't generate a warning if I change in print2()
for (cnt=0; cnt<5; cnt++)
to
for (cnt=0; cnt<6; cnt++)
and lets me access (*p)[5], though I think at least a warning should be
generated here.


That's hard as it has to follow what your program is doing, not just
the syntax. It's certainly possible to warn, though; some lint
programs would.


I don't think its hard to follow what it is doing. At least, the type is
pointer to the array of 5 integers, not 6 or more. A warning IMO is due in
this case too, not only when I use the array of 5 integers directly (w/o a
pointer to it).
It doesn't warn me if I put
aInt3[6] = 0;
into main(). But in both cases the compiler "knows" the real size of the
array, still no warning...


That's easy to warn about and GCC should do it. I suggest you file an
enhancement request.


I guess this enhancement request will be ignored or flamed or something...
The world is envaded by the code like this:
typedef struct tMessage {
long Type;
size_t AmountOfAttachedData;
char aAttachedData[1];
} tMessage;
tMessage* pMsg;
pMsg = GetMyMessage();
Which assumes reading and writing to pMsg->aAttachedData[] at indices
greater than 0. :(

Alex
Nov 15 '05 #41

P: n/a
"Old Wolf" <ol*****@inspire.net.nz> wrote in message
news:11*********************@g49g2000cwa.googlegro ups.com...
Alexei A. Frounze wrote:

I have a question regarding the gcc behavior (gcc version 3.3.4).
You got an unusually high number of garbage responses :)
On the following test program it emits a warning:
#include <stdio.h>

int aInt3[5] = {0,1,2,4,9};

void print2 (const int (*p)[5])
{
size_t cnt;
for (cnt=0; cnt<5; cnt++)
printf ("%d\n", (*p)[cnt]);
}

int main()
{
print2 (&aInt3); // <-- warns here
return 0;
}

MOD.c:: warning: passing arg 1 of `print2' from incompatible pointer

type
print2 is expecting a pointer to an array of constant ints.

Note, you can't have a "const array" in C -- you can
only have an array whose members are all const.

aInt3 is an array of ints, and there is no implicit conversion
in C from pointer-to-array-of-T to pointer-to-array-of-const-T
(or an array of anything else, for that matter). This could be
considered a language defect.

But, this does work:
typedef int (*P5INT)[5];
void print2(const P5INT p)
{

AFAIK it's not possible to do this without a typedef.


I presume you wanted to write something like this:

typedef int(tArrayType)[5];
tArrayType arr = {0,1,2,3,4};

void print3 (const tArrayType* p)
{
int i;
for (i=0; i<5; i++)
printf ("%d\n", (*p)[i]);
}

int main()
{
print3 (&arr);
return 0;
}

But this too issues a warning unless I have arr being const or remove const
from print3().
Same thing, same warning.

Alex
Nov 15 '05 #42

P: n/a
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au...
....
That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which can
be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it is
an access of the second "5 element integer array" element of ap.


OK, I agree with this kind of double indirection.

The prob is though that we have different semantics for pointer to some
object being not an array and for pointer to some object being an array in
the sense that these two objects are treated differently. If this is because
the 2nd pointer is seen as a pointer to pointer (simply because it
unfortunately points to an array) and we have such restrictions on pointers
to pointers, then something is wrong in C or gcc. Like I say in the other
today's post, I don't see a good reason why an attempt to enforce treatment
of some object as being constant (throught the use of a pointer to constant)
is considered bad.
Let's then forget about the array and indeed switch to a pointer to pointer:
char c = 'A';
char *p = &c;
char **pp = &p; // OK
const char **pp_ = &p; // warned
But all what type of pp_ means is that I cannot modify a char that is
somehow doubly dereferenced by pp_. And I think I must be allowed to have
this kind of assignment (pp_ = &p; in the above) because instead of
loosening the protection I try to enforce it. This is the point now.

Alex
Nov 15 '05 #43

P: n/a
"Tommi Johnsson" <TE*@Merlin.Mirrorland> wrote in message
news:Qq*****************@reader1.news.jippii.net.. .
....
Try this one...
Array decays to pointer while array is passed to the function...

int aInt[5] = {1,2,3,4,5};

void print (const int p[5]) {
int x = 25;
if (__builtin_types_compatible_p (typeof (p), const int * ))
printf ("trallalalaa...");
printf ("%d %d %d\n", sizeof (p), sizeof (int[5]), sizeof (const
int *));
//*p[0] = 3;
printf ("%d\n", p[0]);
p = &x;
printf ("%d\n", *p);
}

int main()
{
printf ("test begin\n");

print (aInt);

printf ("test end\n");
return 0;
}
- jt


So, this way I'll pass a pointer to aInt[0], which is OK, but there would
still be no warning no nothing if I try to pass as argument some aInt_
defined as:
int aInt_[6] = {1,2,3,4,5,6};
or as:
int aInt_[4] = {1,2,3,4};
I mean, that [5] in the argument list doesn't mean anything to the compiler.
It wouldn't warn if smaller/bigger array was used. Merely a comment-like
statement :) As if you wrote an operator like this somewhere in the code:
0;
:)
Alex
Nov 15 '05 #44

P: n/a
"Maxim S. Shatskih" <ma***@storagecraft.com> wrote in message
news:da***********@gavrilo.mtu.ru...
An array is one layer of indirection. Given its similarity to a pointer I don't see much controversy in that statement. A pointer to an array is
therefore a second layer of indirection. What do you find disagreeable
about this reasoning?
The C notion of the array is another. Array is the same as pointer to its

first element (in all operations except sizeof(), and so ( p + a ) offset
operations).
What is "the pointer" to which you are referring?


MyArray and &(MyArray[0]) is the same in all contexts except sizeof().
absurd - a pointer to an array is much more than just an address.


In C and C++, it is the same.
doubt that you mean that. Generally a pointer is a variable...


Pointer is a value. Value != variable.


Any value needs storage, including the address that is stored in a special
variable called a pointer. :)

Alex
Nov 15 '05 #45

P: n/a
"Andrey Tarasevich" <an**************@hotmail.com> wrote in message
news:11*************@news.supernews.com...
Alexei A. Frounze wrote:
...
So, I presume nobody knows what's wrong. I haven't found anything on this particular thing in C99. Maybe it's just gcc's way to do things... I need more statistics.
...
What's wrong in the original case is perfectly clear here. The warning is

a consequence of C language's const-correctness rules when they are applied to arrays (and it's been mentioned here already).

Simply speaking, in accordance with C language's const correctness rules, you can perform an implicit 'T* -> const T*' conversion. Often people assume that, say, 'int (*)[10] -> const int (*)[10]' conversion also belongs to that category and should be performed implicitly without any warnings (that's what you
assumed, apparently). Unfortunately, this is not the case. In C language it is not possible to const-qualify an array type as a whole. Period. Any attempts to const-qualify an array type will actually const-qualify the type of the array _elements_ not the array type itself. In other words, there's no situation in C when the 'T* -> const T*' can be applied to pointers-to-arrays, since the proper destination type cannot ever exist in C.

Best regards,
Andrey Tarasevich


Which means C's types are wrong since the T that is an array is treated
differently from T that is not.
If we define:
typedef int(tArrayType)[5];
then still an object of type tArrayType is pretty much different from say
typedef struct tArrayType {/*some member(s)*/} tArrayType;
In the first case we'll get a warning when passing &T to a function
declaring
argument as "const* T" but we won't get the warning in the second case.

Alex

Nov 15 '05 #46

P: n/a
On Mon, 11 Jul 2005 17:35:54 +0000, Chris Torek wrote:
[Given "int arr[N];" and considering "&arr" vs "&arr[0]")
On Sun, 10 Jul 2005 19:51:22 +0400, Alexei A. Frounze wrote:
It's not. :) The values are identical, but the types aren't, strictly
speaking.
In article <pa****************************@dodo.com.au>, Netocrat
<ne******@dodo.com.au> wrote:
Everything else you've said is spot on, but this is slightly incorrect.
Actually, it is completely correct. :-) But it does not tell you all that
much by itself: as I have shown before, the values of 3 and 3.14 are
identical too:

int i = 3;
double d = 3.14;

if ((char)i == (char)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");

Obviously they are only "identical" after conversion to a common type --
in this case "char" -- and the results may (and do) change if we pick a
different common type:

if ((float)i == (float)d)
puts("3 and 3.14 are identical");
else
puts("3 and 3.14 are different");

To compare &arr against &arr[0], we have to convert to a common type; and
as with the int/double arrangement above, this may change the value(s) in
the process:


Point taken.
#include <stdio.h>
int glob_array[5];

int main(void)
{
int fn_array[5];

if ((&glob_array != glob_array) || (&fn_array != fn_array))
printf("I haven't seen a situation like this before.\n");
}
}

If you actually compile this,


Which I didn't (obviously).
you get the required diagnostic, and in this
particular case, two more diagnostics:

% cc -O2 -W -Wall -ansi -pedantic -o t t.c t.c: In function `main':
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:8: warning: comparison of distinct pointer types lacks a cast
t.c:10: warning: control reaches end of non-void function

(the C standard requires only that "at least one diagnostic" come out, and
does not say whether it is a "warning", or an "error", or even a
"kumquat"). We can fix this by inserting a conversion to some common
type: for instance, we could cast both to "char *". But introducing a
conversion gets us back to that 3==3.14 problem. I think the real question
boils down to whether &arr and &arr[0] will compare equal under *all*
"well-defined" conversions -- which may even be only those to "char *" and
"void *" -- and then I think the answer is "yes", so that we can in fact
say that the converted values are always identical as long as we do a
sensible conversion.
You "think" the answer is "yes", Chris Crough in his reply asks "Is that
actually defined by the standard?" and in my original post I wrote "I
don't know however, whether this is mandated by the standard - in theory
it isn't necessary for it to be true". None of us know for sure...
But, onward:
However in the context of a function parameter, it is not true. Given
that in C parameters are passed by value, it's not possible for the
address of the array parameter to equal the address of the original
array and therefore it's not possible for the address of the array
parameter to equal the address of the first element that it points to.
i.e. we can write:

#include <stdio.h>
void somefunction(int arrayparm[5])
{
if (arrayparm == &arrayparm)
printf("Something impossible has occurred.\n");
}
}

The real problem here is "what you see, well, all of it's a lie"[%]. The
variable named "arrayparm" has type "pointer to int", not "array 5 of
int". We can expose the lie via various operators:

/* these sizes will differ (unless you get VERY unlucky) */
printf("sizeof (int [5]) = %lu\n", (unsigned long)sizeof (int [5]));
printf("sizeof arrayparm = %lu\n", (unsigned long)sizeof arrayparm);

/* cannot do this with an array */
arrayparm = NULL;

and of course, your own example, once we insert some appropriate
conversions to eliminate the need for a diagnostic (and perhaps no
executable program as a consequence of the diagnostic):

printf("%p != %p, we presume\n", (void *)arrayparm, (void
*)&arrayparm); if ((void *)arrayparm != (void *)&arrayparm)
puts("we presumed correctly");
else
puts("uh oh");

[% "Wine from the Water", from Try Anything Once]


Right, right, of course... an array decays into a pointer when passed as
a parameter to a function. I had forgotten that. So I was treating a
pointer as an array and making the wrong deductions. It does seem then
that there is no case where (void*)&array is necessarily different to
(void*)array... leaving the question, as Chris Crough puts it, of whether
'pre-standard C compilers [implementing] arrays ... as pointers ... [is a
type of] expansion actually banned by the standard, or [whether it is]
"just not the done thing"?'

Nov 15 '05 #47

P: n/a
On Mon, 11 Jul 2005 21:33:32 +0400, Maxim S. Shatskih wrote:
An array is one layer of indirection. Given its similarity to a pointer
I don't see much controversy in that statement. A pointer to an array
is therefore a second layer of indirection. What do you find
disagreeable about this reasoning?
The C notion of the array is another.


You are just repeating my first statement, because by "array" of course I
meant "the C notion of the array" - we are talking in a C newsgroup after
all. You seem to be implying that there is a third layer of indirection
different from the two I described... I just don't understand your point.
Array is the same as pointer to its
first element (in all operations except sizeof(), and so ( p + a )
offset operations).


True, but of what relevance is that statement? You are supposedly, after
all, disagreeing with my statement that "A pointer to an array *is* double
indirection." How does this support your case?
What is "the pointer" to which you are referring?


MyArray and &(MyArray[0]) is the same in all contexts except sizeof().


As Chris Torek pointed out in another part of this thread, that statement
is not actually correct. They are different types. But yes, we all
seem to agree that the values will be the same for sensible conversions.

That statement does not, however, answer my question, which was which
pointer you are referring to.
absurd - a pointer to an array is much more than just an address.


In C and C++, it is the same.


No, it is not the same. A pointer is not an address. It is a type
whose value represents an address.
doubt that you mean that. Generally a pointer is a variable...


Pointer is a value. Value != variable.


A pointer is a type containing a value. Container of value != value.

You still haven't explained why you disagree with my statement that a
pointer to an array is double indirection.

Nov 15 '05 #48

P: n/a
On Tue, 12 Jul 2005 10:32:10 +0400, Alexei A. Frounze wrote:
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au...
On Mon, 11 Jul 2005 09:29:27 +1000, Netocrat wrote:
> [D]ouble indirection can easily be used to gain access to the
> supposedly protected const type by assigning the middle pointer to a
> non-const pointer. There's no way the compiler can detect this, so
> disallowing automatic const-conversion for double-indirection
> parameters makes sense.
I'm talking nonsense. You can't assign the middle pointer to a
non-const pointer without a cast. But you can use the automatic
conversion to violate the const protection: quoting "Me" in another
thread:

const char c = 'c';
char * pc;
const char ** pcc = & pc ; /* not allowed */
*pcc = & c;
*pc = 'C'; /* would modify a const object if the conversion above were
* allowed */


Correct, but I don't think it's a good example.


I think it's a great example for what it's intended to show. What it
shows is that the const protection you are giving your c variable is
useless if a char ** variable can be automatically cast to const char **.
So really it's showing: if you want to be able to trust that the const
qualifier actually does what it's supposed to do, then automatic
conversions from char ** to const char ** _cannot_ be allowed.

It may not be as useful in explaining how this relates to your case. You
seem to be arguing that an array should be treated as though it were a
simple type, rather than as an indirected type, in this case. Actually I
don't see any problems with doing that. The trick above can't be used
when pc is declared as a char array rather than char pointer, since then
we can't change its base address. So perhaps you could argue something
like this:

Since the type char [] is fundamentally different from char * in that the
base address of the variable it defines cannot be modified, the automatic
conversion from char (*)[] to const char (*)[] is not unsafe, as the
automatic conversion from char ** to const char ** is, and should be
allowed.

I don't see any problems with this statement (others may...). But the
point is, regardless of whether this statement is true or not, it seems to
me (and again I must reiterate that I don't know what the standard says on
this) that C does treat these types equivalently for const-casting
purposes.
Simply being able to
modify something by pc and being unable to modify it by ppc is just fine,
so is in the simpler example:
char c = 'A';
char *pc = &c;
const char *pc_ = &c;
*pc = 'B'; // OK
*pc_ = 'B'; // prohibited
Yes this is all OK because the automatic conversion of &c from type
char* to type const char* can not be used in any way to surreptitiously
write to any const-protected values.

This "simpler" example is indeed just that - because it doesn't deal with
double indirection or pointers to array at all - which is the case in
point. If you really want to use a simple example that applies to our
discussion, we could change the character types to character array types
and extend it thus:

char c[5] = "abcde";
char (*pc)[5] = &c;
const char (*pc_)[5] = &c; /* warning - prohibited */
(*pc)[1] = 'B'; /* OK */
(*pc_)[1] = 'B'; /* prohibited */

This illustrates your case better. As I have argued above - to echo
what I understand to be your fundamental argument - there is no semantic
reason for prohibiting the automatic casting of &c from char (*)[5] to
const char (*)[5]. Nevertheless in C it is prohibited. C'est la vie.
Apparently the casting rules are the same as for char ** to const char **
- for which there _is_ a good reason for prohibition. We might not think
it necessary or appropriate, but that's just the way C works in this case.

Another note - // comments are only allowed by the standard in C99, and
since you didn't specifically mention using C99 I presume you are not
using switches on gcc to invoke standards-compliant behaviour at all,
which you really should. Using -ansi -pedantic makes it reject non-C90
compliant code and using -std=C99 -pedantic does same for C99. -W and
-Wall are good for additional non-standard-specific warnings.
This is how most of libc's functions are declared -- their arguments are
of type of a pointer to a constant value.
I think you mean "const-qualifed type" rather than "constant value", but I
understand you.
This is what I'd like to have
with the array too. I'm not really sure why enforcing protection in this
simple case above is OK (i.e. pc=&c;) but not OK in case of using the
array as an object to be passed by reference/pointer.
Neither am I because it doesn't seem to serve any protective purpose,
but as I've tried to explain it seems to be because the array is being
treated equivalently to the case of a pointer, where a protective purpose
_is_ served.
I'm fine with
warnings and errors caused by the improper use of a pointer to a
constant object, e.g. attempt to modify the constant object. That's
perfectly understandable. Why cannot I enforce such a protection by
treating some object (not necessarily one defined as constant) as a
constant one
You can in some simple cases as your example shows, so I don't know why
you're arguing here that you cannot.
-- that's something I don't get, no matter if there's
double indirection or not.
Double indirection in the sense of char ** (but not in the sense of
char(*)[]) _does_ matter though, as the example I quoted shows.
I'm puzzled. What else am I missing?
You're totally missing the point of the example I quoted if you want to
maintain that double indirection of the form char ** should not be taken
into account when performing automatic const conversions. Double
indirection in the form char (*)[] of course is different in semantics but
apparently treated by C in the same way as char **.

Note that once we get to char (**)[] then this is a double pointer and
semantically truly does require prohibition of automatic const conversion.

Now to respond to the message you posted elsewhere:

On Tue, 12 Jul 2005 11:06:33 +0400, Alexei A. Frounze wrote:
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au... ...
That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which
can be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it
is an access of the second "5 element integer array" element of ap.
OK, I agree with this kind of double indirection.

The prob is though that we have different semantics for pointer to some
object being not an array and for pointer to some object being an array in
the sense that these two objects are treated differently.


Well that's not a totally accurate statement of the problem, because in
some cases (ie when that "some object" is a pointer) there really _is_
a need for different treatment as "Me"'s example shows. But if you
rewrite that statement as "We have different semantics for pointer to
array and for pointer to any other non-pointer type", then I agree.

There doesn't seem to be a compelling argument for pointer to array being
treated any differently to other non-simple types, such as structs. To
again modify your simple example:

struct s {
int x;
int y;
};

struct s c;
struct s *pc = &c;
const struct s *pc_ = &c; /* no prohibition here as there is when c is an
* array */
pc->x = 1; /* OK */
pc_->x = 2; /* prohibited */
If this is
because the 2nd pointer is seen as a pointer to pointer (simply because
it unfortunately points to an array)
As I've explained I believe that's the cause, but I don't know the
standard well enough to confirm this.
and we have such restrictions on
pointers to pointers,
For good reason, as the example I quoted shows.
then something is wrong in C or gcc.
That's a strong statement, and clearly as it applies to char ** conversion
its inaccurate, but as it applies to treating pointers to arrays
equivalently with double pointers, in this case your opinion that
"something is wrong in C" appears to be at the least a proposition that
could reasonably be argued.
Like I say in
the other today's post, I don't see a good reason why an attempt to
enforce treatment of some object as being constant (throught the use of
a pointer to constant) is considered bad. Let's then forget about the
array and indeed switch to a pointer to pointer:
char c = 'A';
char *p = &c;
char **pp = &p; // OK
const char **pp_ = &p; // warned
But all what type of pp_ means is that I cannot modify a char that is
somehow doubly dereferenced by pp_. And I think I must be allowed to
have this kind of assignment (pp_ = &p; in the above) because instead of
loosening the protection I try to enforce it. This is the point now.


But Alex you're now ignoring the lesson of the original example I quoted.
You're effectively saying, "the automatic conversion from char ** to
const char ** may have caused problems in Me's example, but it doesn't
in this case so it should be allowed here." Well and good, but in general
the compiler can't know when such an automatic conversion would cause
problems and when it wouldn't, which is why there is a rule that applies
in _all_ cases.

So in summary:
(a) it appears that there is no way around your problem without using a
cast. The cast doesn't appear to violate any const-protection semantics
as it would in the case where aInt3 was declared int * rather than int[5].
Casts in general are unwise though because they can mask useful (or
required) warnings, so be wary before using one.
(b) the prohibition of an automatic cast in this case does seem according
to const safety semantics to be unnecessary.

Nov 15 '05 #49

P: n/a
On Tue, 12 Jul 2005 11:06:33 +0400, Alexei A. Frounze wrote:
"Netocrat" <ne******@dodo.com.au> wrote in message
news:pa****************************@dodo.com.au... ...
That's true, but a pointer to an object can be treated as an array of
those objects and this is no less true for pointers to arrays - which
can be treated as arrays of arrays. So for index other than 0

ap[index] != (*ap)[index]

In fact accessing ap[1] in this instance is illegal but conceptually it
is an access of the second "5 element integer array" element of ap.


OK, I agree with this kind of double indirection.

The prob is though that ...


<snip contents>

I integrated my reply to this post of yours with my reply to another of
your posts. The message-id of that other reply is
<pa****************************@dodo.com.au>

Nov 15 '05 #50

204 Replies

This discussion thread is closed

Replies have been disabled for this discussion.