constness problem

T

Tim Woodall

How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
char arr[12][12];
};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
test_func(cdata.arr);
test_func(data.arr); /* Line 13 */
}

$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr.c
$

It appears to be OK in C++ but not in C. I'm guessing that I'm missing a
const somewhere but I cannot work out where.

I've even tried a typedef const char ARR[12]; and then const ARR* data
parameter but that hasn't worked either. I get exactly the same warning
when I try to pass the non-const version.

(gcc 4.3.2 in case it's a bug in gcc that has been fixed in a later
version)

Tim.
 
B

bartc

Tim said:
How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
char arr[12][12];
};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
test_func(cdata.arr);
test_func(data.arr); /* Line 13 */
}
It appears to be OK in C++ but not in C. I'm guessing that I'm
missing a const somewhere but I cannot work out where.

Have your tried just getting rid of all the consts?
 
T

Tom St Denis

How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
  char arr[12][12];

};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */

}

$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr.c
$

You're passing it a char * that is not const. The struct is const.

Tom
 
T

Tim Woodall

How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
  char arr[12][12];

};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */

}

$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr.c
$

You're passing it a char * that is not const. The struct is const.
That doesn't make sense. I'm not passing a char*, I'm passing a
char (*)[12]

If the struct is const then any member had better be const otherwise I
can change the struct by passing a pointer to a member.

The line that is giving the problem is not passing a member of a const
struct. The const struct case is working.

I had assumed that this problem was related to:
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
but it's not quite the same.

However, it appears that gcc also does not like what that says is ok.

void test_func(const char* const * data);

void testme(void)
{
char ** p = 0;
test_func(p);
}

$ gcc -W -Wall -ansi -pedantic -c arr2.c
arr2.c: In function 'testme':
arr2.c:6: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr2.c
$

Tim.
 
B

Ben Bacarisse

Tim Woodall said:
How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
  char arr[12][12];

};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */

}

$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr.c
$

You're passing it a char * that is not const. The struct is const.
That doesn't make sense. I'm not passing a char*, I'm passing a
char (*)[12]

If the struct is const then any member had better be const otherwise I
can change the struct by passing a pointer to a member.

The line that is giving the problem is not passing a member of a const
struct. The const struct case is working.

I had assumed that this problem was related to:
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17
but it's not quite the same.

However, it appears that gcc also does not like what that says is
ok.

Yes, C and C++ have different rules in this area.

I don't think you can avoid a cast in this case. You can, of course,
ditch all the const qualifiers, but on balance I think they pay their
way -- even though you are sometimes forced to persuade the compiler
to accept your code.

<snip>
 
T

Tim Woodall

Yes, C and C++ have different rules in this area.

I don't think you can avoid a cast in this case. You can, of course,
ditch all the const qualifiers, but on balance I think they pay their
way -- even though you are sometimes forced to persuade the compiler
to accept your code.
Thanks. I didn't know C and C++ were different here (and, ironically
although I would say I knew a lot more C than C++ I knew the C++ rule
for this case rather than the C rules and assumed either I was doing
something silly or it was a compiler bug)

Tim.
 
T

Tom St Denis

How do I get gcc to like the following code (other than the obvious
cast)?
struct DATA {
  char arr[12][12];
};
void test_func(const char (*data)[12]);
const struct DATA cdata = {{{0}}};
struct DATA data;
void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */
}
$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr.c
$
You're passing it a char * that is not const.  The struct is const.

That doesn't make sense. I'm not passing a char*, I'm passing a
char (*)[12]

If the struct is const then any member had better be const otherwise I
can change the struct by passing a pointer to a member.

Whoops ya whatever, you're still not passing it a const.

Tom
 
L

lawrence.jones

Tim Woodall said:
How do I get gcc to like the following code (other than the obvious
cast)? [...]
It appears to be OK in C++ but not in C. I'm guessing that I'm missing a
const somewhere but I cannot work out where.

You're not missing anything, the C rules are different than the C++
rules and don't handle that case. You have to use the cast.
 
M

mohangupta13

How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
  char arr[12][12];

};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */
}

$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type
$ g++ -W -Wall -ansi -pedantic -c arr.c
$

It appears to be OK in C++ but not in C. I'm guessing that I'm missing a
const somewhere but I cannot work out where.

I've even tried a typedef const char ARR[12]; and then const ARR* data
parameter but that hasn't worked either. I get exactly the same warning
when I try to pass the non-const version.

(gcc 4.3.2 in case it's a bug in gcc that has been fixed in a later
version)

Tim.
I don't understand what is logically wrong to increase the strictness
of a datatype when passed to a function like
int a;
funct(a);

int funct(const int);

now here by passing 'a' i am actually imposing some stricter condition
on it ,so why should that be not allowed. I can never do any harm (as
i see).

thanks
Mohan
 
B

Ben Bacarisse

mohangupta13 said:
How do I get gcc to like the following code (other than the obvious
cast)?

struct DATA {
  char arr[12][12];

};

void test_func(const char (*data)[12]);

const struct DATA cdata = {{{0}}};
struct DATA data;

void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */
}

$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type

[It's best to trim sigs.]
I don't understand what is logically wrong to increase the strictness
of a datatype when passed to a function like
int a;
funct(a);

int funct(const int);

now here by passing 'a' i am actually imposing some stricter condition
on it ,so why should that be not allowed. I can never do any harm (as
i see).

No, it can't in that case and of course that example is fine. So is:

int a;
void f(const int *ap);
f(&a);

gcc will not complain. The problem occurs when the const qualifier is
being "added" at anything more than the first level of indirection.
The classic example being passing a T ** value to a function that
expects a const T **.

The problem is that adding a const at this second level is not safe:

#include <stdio.h>

const char foo = 'X';

void f(const char **cpp)
{
*cpp = &foo;
}

int main(void)
{
char *cp;
f(&cp); /* not permitted */
*cp = '!';
printf("c = %c\n", foo);
return EXIT_SUCCESS;
}

The problem is to come up with a set of rules that allows safe
assignments and parameter passing whilst stopping all those that are
unsafe. The C committee opted for simple wording[1] that sometimes
forbids a case the is safe.

[1] Roughly: "the type pointed to by the LHS has all the qualifiers of
the type pointed to by the RHS" for assignment and the function
calling is the defined in terms of assignment.

<snip>
 
M

mohangupta13

mohangupta13 said:
How do I get gcc to like the following code (other than the obvious
cast)?
struct DATA {
  char arr[12][12];
};
void test_func(const char (*data)[12]);
const struct DATA cdata = {{{0}}};
struct DATA data;
void testme(void)
{
  test_func(cdata.arr);
  test_func(data.arr);   /* Line 13 */
}
$ gcc -W -Wall -ansi -pedantic -c arr.c
arr.c: In function 'testme':
arr.c:13: warning: passing argument 1 of 'test_func' from incompatible
pointer type

[It's best to trim sigs.]
I don't understand what is logically wrong to increase the strictness
of a datatype when passed to a function like
int a;
funct(a);
int funct(const int);
now here by passing 'a' i am actually imposing some stricter condition
on it ,so why should that be not allowed. I can never do any harm (as
i see).

No, it can't in that case and of course that example is fine.  So is:

  int a;
  void f(const int *ap);
  f(&a);

gcc will not complain.  The problem occurs when the const qualifier is
being "added" at anything more than the first level of indirection.
The classic example being passing a T ** value to a function that
expects a const T **.

The problem is that adding a const at this second level is not safe:

  #include <stdio.h>

  const char foo = 'X';

  void f(const char **cpp)
  {
       *cpp = &foo;
  }

  int main(void)
  {
       char *cp;
       f(&cp); /* not permitted */
       *cp = '!';
       printf("c = %c\n", foo);
       return EXIT_SUCCESS;
  }

The problem is to come up with a set of rules that allows safe
assignments and parameter passing whilst stopping all those that are
unsafe.  The C committee opted for simple wording[1] that sometimes
forbids a case the is safe.

[1] Roughly: "the type pointed to by the LHS has all the qualifiers of
the type pointed to by the RHS" for assignment and the function
calling is the defined in terms of assignment.

<snip>

thanks ben for the detailed explanation , silly me i did read this
some time back but forgot .
thanks
Mohan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,602
Members
45,182
Latest member
BettinaPol

Latest Threads

Top