Solved

Strange gcc warning message

Posted on 2002-04-29
42
393 Views
Last Modified: 2006-11-17
Hello.

When compiling the following, gcc gives this warning:
test.c:7: warning: passing arg 1 of `foo' from incompatible pointer type

The code is:

void foo(const int b[8][8]){

}

int main(){
  int b[8][8];
  foo(b);
  return 0;
}

Any ideas why?
Please don't post answers - only comments. I will accept a correct comment as answer.

Alexander Maryanovsky.
0
Comment
Question by:Sasha_Mapa
  • 18
  • 10
  • 4
  • +6
42 Comments
 
LVL 10

Expert Comment

by:makerp
ID: 6976959
try removing the const, do you still get it?
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6977011
Of course not...

Alexander Maryanovsky.
0
 
LVL 10

Expert Comment

by:makerp
ID: 6977027
well then, its because a const pointer is not campatable with a non-const pointer :)
0
 
LVL 18

Expert Comment

by:deighton
ID: 6977309
int main(){
 int b[8][8];
 foo((const int **) b);
 return 0;
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6977331
Well, first of all it doesn't answer my question, and second of all, gcc still gives me the exact same warning with that explicit cast.

Alexander Maryanovsky.
0
 
LVL 16

Expert Comment

by:Peter Kwan
ID: 6977414
How about:

void foo(const int b[8][8]){

}

int main(){
 const int b[8][8] = { /* ARRAY DATA */ };
 foo(b);
 return 0;
}
0
 
LVL 6

Expert Comment

by:zebada
ID: 6978467
This compiles with no warnings under gcc

void foo(const int b[8][8]){
  int i,j;

  for ( i=0 ; i<8 ; i++ ) {
    for ( j=0 ; j<8 ; j++ )
      printf("%d,",b[i][j]);
    printf("\n");
  }
}

int main(){
  int b[8][8];
  int i,j;

  for ( i=0 ; i<8 ; i++ )
    for ( j=0 ; j<8 ; j++ )
      b[i][j] = i*10+j;

  foo((const int (*)[])b);
  return 0;
}

Just to make sure the data was passed correctly to foo(), the output is:
0,1,2,3,4,5,6,7,
10,11,12,13,14,15,16,17,
20,21,22,23,24,25,26,27,
30,31,32,33,34,35,36,37,
40,41,42,43,44,45,46,47,
50,51,52,53,54,55,56,57,
60,61,62,63,64,65,66,67,
70,71,72,73,74,75,76,77,
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6978857
pkwan: I need a non-const array in the calling method.

zebada: I don't want to do the horrible explicit cast, why should I? My question is not how to "fix" the problem, but why doesn't gcc like it? It looks like perfectly valid code to me...

Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6978922
It may look like perfectly valid code but it is not.

The compiler will make certain assumptions (usually to do with optimising the code) based on the const modifier.

In the foo() function the compiler is legally allowed to assume that the values in the array will NOT change during the execution of the function. That may enable it to do some tricky optimisations that otherwise would not be "safe".

It is very easy to trick a compiler into letting you change the contents of a const array using totally unrelated pointers to the data in the array. To prevent this and to try to honour the const modifier some compilers (gcc included, I believe) will place const data and things like string literals into read only memory. The read-only is enforced by the operating system. Try to write to read-only memory usually causes a SIGBUS core dump.

That means the compiler requires you to only ever pass const arrays to the foo() function.

If you want/need to move outside of the program's own declarations the compiler warns you that you are not providing a const array where the program has declared one is required. It is telling you that the read-only requirment may not be enforced correctly, and that you cannot rely on the contents of the array that you passed to foo() being the same as when you called foo().

If you *really* need to do that then the compiler provides the option of casting. That means you are overriding the type declaration and telling the compiler that you understand the risks involved but you KNOW that the array data will not change during the execution of the foo function.

Paul
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6979124
I'm sorry, this seems to contradict what I know and a test I just ran.

What I know - "const" is not for the compiler, it's for the developer. Marking an argument as const simply prevents you from making a mistake and later modifying what you've marked as const.

A test - I added a for loop into the foo(const int b[8][8]) function which printed the array and compiled with -03. I then removed the const modifier and compiled again. The two resulting binaries were identical. If the compiler was using my "const" hint to do something special, it would've produced a different binary - no?

Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6979335
The platform on which you are running may not support "read-only" memory.

By the way
const IS DEFINITELY for the compiler.
Comments are for the developer.

I hope the following code examples make the use of const a little clearer.
 
This code with the const modifier on line 3:
#include <stdio.h>

const int i=5;

void foo(const int *i){
  *i = 10;
}

int main(){
  printf("Before %d\n",i);
  foo((const int *) &i);
  printf("After %d\n",i);
  return 0;
}

Here's the compile with warnings and the BUS-ERROR.
And the executable checksum:

uranus:/opt/pb> gcc -o t t.c
t.c: In function `foo':
t.c:6: warning: assignment of read-only location
uranus:/opt/pb> ./t
Before 5
Bus error(coredump)
uranus:/opt/pb> sum t
64714 120 t

Now take this code without the const modifier on line 3:
#include <stdio.h>

int i=5;

void foo(const int *i){
  *i = 10;
}

int main(){
  printf("Before %d\n",i);
  foo((const int *) &i);
  printf("After %d\n",i);
  return 0;
}

Here's the compile with the warnings - no BUS-ERROR.
And the executable checksum is different.
uranus:/opt/pb> gcc -o t t.c
t.c: In function `foo':
t.c:6: warning: assignment of read-only location
uranus:/opt/pb> ./t
Before 5
After 10
uranus:/opt/pb> sum t
774 120 t
uranus:/opt/pb>

P.S. I don't place too much faith in the fact that the binaries have different checksums. I can compile the same source code and still get different checksums on the binaries. HP-UX probably sticks a date/time stamp into the binaries.

However you can see that by adding the const modifier to the global integer declaration the program failed with a SIGBUS error because it tried to write to read-only memory.

Regards
Paul

0
 
LVL 3

Expert Comment

by:elfie
ID: 6980106
AFAIK, if variables are defined as 'const' they 'can' be paced in the 'code' part of a program. Normal variables are put in the 'data'part. At run-time, the 'code' part is read only, since it can be shared amongst other users. (data can't).

'const' is definitly used by the compiler an linker.

the compiler uses it for optimisations.

suppose you have something like
void foo(const int b[8][8]){
int a;
a=b[1][1];
foo_bis(b);
a=b[1][1];
}

the compiler will know that b is defined 'const', a is a local variable, so a cannot be changed due to the call of foo_bis, and b cannot be changed due to be 'const'.

the pseudo-assembly code lookss like
  load b[1][1]
  store a
  load b
  call foo_bis
  return
This means that inside the exe, the code a=b[1][1] will be in it only once.
If b was not declared const, b could change within foo_bis, and the code a=b[1][1] must be generated twice.
the pseudo-assembly code lookss like
  load b[1][1]
  store a
  load b
  call foo_bis
  load b[1][1]
  store a
  return

hope this helps
0
 
LVL 1

Expert Comment

by:snoopym
ID: 6980110
try

void foo(const int b[][8]){
}
0
 
LVL 3

Expert Comment

by:elfie
ID: 6980112
So since the compiler notices that b is not defined as 'const' it generates a warning telling you that the behavior of the program can be different than the one you expected.

based on the above write a foo_bis that modifies the value b[1][1], and do a printf after each a=b[1][1] assigment.

you'll see what happens....
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6980565
zebada, your 1st example coredumps because the actual memory you're trying to modify was reserved as const (read only). Your 2nd example demonstrates exactly why my code is fine! In my piece of code, the array is also defined non-const, just like the i in your 2nd example.

What you are saying is that I'm lying to the compiler by passing a read-write piece of memory to a function that takes a read-only piece of memory. This isn't lying - the compiler can still do all the read-only optimizations within the function, because *for that function* the memory is read only.

Alexander Maryanovsky.
0
 
LVL 3

Expert Comment

by:elfie
ID: 6981059
have a look my explanation

if you have
void foo(const int b[8][8]){
int a;
a=b[1][1];
foo_bis(a, b);
a=b[1][1];
printf ("%d",a);
}

and modify the content of b in the function foo_bis,
(b must be defined as normal int b[8][8] in main),
the value printed in 'a' should be the first one (and  not the second one).

When compiling without optimisatie the second value 'van' be passed.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6981661
> and modify the content of b in the function foo_bis,

If foo_bis takes a regular (non const) int b[8][8] parameter, the code will not compile because you're not allowed to cast a const pointer to a non-const pointer (but vice versa is perfectly ok).

Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6981837
>zebada, your 1st example coredumps because
>the actual memory you're trying to modify
>was reserved as const (read only).

That was my point exactly.

>What you are saying is that I'm lying to
>the compiler by passing a read-write piece
>of memory to a function
>that takes a read-only piece of memory.

Not lying - overriding the limited understanding the compiler has of the *logic* of your program. There are things that a compiler cannot know that only a programmer can know. You are just "explaining" to the compiler that its OK to do what you want and that you as a programmer are aware of the risks involved. In your case there is no risk involved - you *know* that foo() does not change the value of the const data.

>This isn't lying - the compiler can still
>do all the read-only
>optimizations within the function,
> because *for that function* the memory is read only.

Exactly, but here's the point that I was making that you didn't seem to understand:

By declaring a parameter as const you are telling the compiler that the value CANNOT change. This is a very different thing from telling the compiler that the FUNCTION WILL NOT change the value.

The compiler CANNOT enforce read-only memory. The operating system must do that. To allow the perating system to enforce read-only memory the data declarations must be compiled/linked into the read-only part of the executable's memory - as elfie said: the text segment.

Here's another example:
Should the output of the following code be: a=5 or a=50?

As a programmer you *know* the output should be a=50, but the compiler/optimiser will not know that problem() is going to change the value of *i. In fact the optimiser has been explicitly told that the value of *i will not change and may remove the second assignment statement.

#include <stdio.h>

int i=5;

void problem() {
  i = 50;
}

void foo(const int *i) {
  int a;
  a = *i;
  problem();
  a = *i;    // this line may be optimised out
  printf("a=%d\n",a);
}

int main(){
  foo((const int *) &i);
  return 0;
}
0
 
LVL 51

Expert Comment

by:ahoffmann
ID: 6982178
void foo(const int b[8][8]){}
int main(){const int b[8][8];foo(b);return 0;}

compiles without warnings, that's correct according C-syntax (K&R, ANSI-C, and comments above)
But it is not what you want, which doesn't matter 'cause the standards for C *had been* defined long ago :-)

Anyway, you might be right that the const in the foo definition is for "programmer's comment", 'cause foo then should not be able to write to the data nevertheless it was called with a const arg or not. And so the compiler warns you (as explained sevaral times above).

Unfortunatelly, compiler implementations differ on the behaviour of such things, IMHO mainly 'cause the optimizer does not put such const variables into the code segment. If these variables are in the code segment, *and* are modified, you'll get a Segmentation fault. If the underlaying OS does not recognize this invalid write, you most likely get a Bus Error, if the code in question will be executed (which might not occour, for several reasons).

If you change a const variable (in foo), it depends if it works (the change) in foo only, or in foo and main, or if you get a segmentation fault. I know of each type of compilers.
Again, this behaviour is independent from the type of parameter (const or not) you pass to foo.

I'm not shure about gcc, but I assume that it behaves wrong here.
So, if you want be shure that your code worjs right, use the
  -pedantic-errors option.

0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6982931
ahoffmann, I didn't understand your comment at all... You'll have to rephrase it if you want me to understand it :-)

Alexander Maryanovsky.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6982951
zebada, so you're basically saying that there's const correctness facility in C? The const is only to hint the compiler that it can do certain optimizations? How does that work in C++, which *does* have const correctness and where casting a normal pointer into a const pointer is valid?

How do you explain that this compiles without any warnings?

void foo(int * a){}

int main(){
  int a = 5;
  int * b = &a;
  foo(b);
  return 0;
}

Wouldn't your arguments which say that the warning is ok apply to this case too?

Alexander Maryanovsky.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 6

Expert Comment

by:zebada
ID: 6983043
I'm sorry Alexander, but I don't understand the point you are making with the code that you supplied.

>so you're basically saying that there's
>const correctness facility in C

Well I'm not 100% sure of the compiler's intention - it may not be that the compiler is enforcing const correction in as much as it is optimising the const declarations into read-only memory. As a side effect of this the read-only restriction is enforced. I don't know enough about C++ to comment on that part of the discussion. In fact you are testing the limits of my C knowledge here as well. Based on this entire discussion and what ahoffmann says above I am rethinking my understanding of this const issue. Some interesting points have been raised.


0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6983084
Oops, it's supposed to be:

void foo(const int * a){}

int main(){
 int a = 5;
 int * b = &a;
 foo(b);
 return 0;
}

Forgot the const in foo().

Alexander Maryanovsky.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6983085
And I also meant:
"so you're basically saying that there's *no* const correctness facility in C?"

Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6984438
I see your point, but have no answer.

Maybe it all comes down to the compiler vendor's implementation of the const keyword.

What does the Ansi 'C' standard say about const function parameters?
0
 
LVL 1

Expert Comment

by:tapasmondal
ID: 6985088

Hi,
I think this solution is correct.
You just type cast when you call the function.
void foo(const int b[8][8]){

}

int main(){
 int b[8][8];
 foo((const int)b);
 return 0;
}


thanks

tapas
0
 
LVL 1

Expert Comment

by:tapasmondal
ID: 6985090
Hi,
I think this solution is correct.
You just type cast when you call the function.
void foo(const int b[8][8]){

}

int main(){
int b[8][8];
foo((const int)b);
return 0;
}


thanks

tapas
0
 
LVL 51

Expert Comment

by:ahoffmann
ID: 6985369
void foo(const int b[8][8]){}
int main(){const int b[8][8];foo(b);return 0;}

compiles without warnings, that's correct according C-syntax (K&R, ANSI-C, and comments above).
If you omit the const in main's declaration of b, you get the warning. This is 100% perfect implementation of gcc.

According your mind that const in the foo declaration is just a "hint for programmer" rather than for the compiler, you're close to the standards, 'cause the standard simply tells that foo **MUST** not change the conntent of b, nevertheless you called foo with a const b or just a (writable) b.

About the rest please reread my comment, then point out the phrases you don't understand.

According, the modification to the code in previous (6..7) comments with "const int *b", keep in mind that this is completetely different to you initial question.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985477
tapasmondal, I specifically asked not to post answers. Also, your "answer" doesn't answer my question AND is wrong (you can't cast int[8][8] into const int.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985601
>What does the Ansi 'C' standard say about const function parameters?

I don't know... I was hoping someone here could explain it for me. Is the complete version available somewhere online? This is all the K&R book says about const:
 
  The const and volatile properties are new with the ANSI standard. The purpose of const is to announce objects that may be placed in read-only memory, and perhaps to increase opportunities for optimization. Except that it should diagnose explicit attempts to change const objects, a compiler may ignore these qualifiers.

ahoffmann:

> Anyway, you might be right that the const in the foo
> definition is for "programmer's comment", 'cause
> foo then should not be able to write to the data
> nevertheless it was called with a const arg or not.
> And so the compiler warns you (as explained sevaral
> times above).

So if I'm right and int[][] can be freely cast into const int[][], why does the compiler warn me? What does it warn me about? What can happen that I did not expect? Why does my last example compile without a warning although it conceptually does the exact same thing as the original example?


Alexander Maryanovsky.


0
 
LVL 6

Accepted Solution

by:
zebada earned 200 total points
ID: 6985737
I've been doing some digging this may help: It uses char instead of int but ther concept is the same.

11.10:     Why can't I pass a char ** to a function which expects a
     const char **?

A:     You can use a pointer-to-T (for any type T) where a pointer-to-
     const-T is expected.  However, the rule (an explicit exception)
     which permits slight mismatches in qualified pointer types is
     not applied recursively, but only at the top level.

     You must use explicit casts (e.g. (const char **) in this case)
     when assigning (or passing) pointers which have qualifier
     mismatches at other than the first level of indirection.

     References: ISO Sec. 6.1.2.6, Sec. 6.3.16.1, Sec. 6.5.3; H&S
     Sec. 7.9.1 pp. 221-2.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985745
Hmm, where is this taken from?

Alexander Maryanovsky.
0
 
LVL 1

Expert Comment

by:tapasmondal
ID: 6985765
Hi sasha,

I am sorry, for my mistake. I think I am right. I check this code. But it has no warning. U just write the above code and compile.


tapas
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985776
tapasmondal:

Here's the result of compiling your code:

test.c: In function `main':
test.c:7: warning: passing arg 1 of `foo' makes pointer from integer without a cast

And even if it compiled - it does *not* answer my question which was not "how do I get rid of this warning?" but "why do I get this warning?".


Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6985833
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985865
tapasmondal:

Here's the result of compiling your code:

test.c: In function `main':
test.c:7: warning: passing arg 1 of `foo' makes pointer from integer without a cast

And even if it compiled - it does *not* answer my question which was not "how do I get rid of this warning?" but "why do I get this warning?".


Alexander Maryanovsky.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985867
Thanks - *that* was the answer I was looking for!

Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6985880
Sorry it took so long - still don't know why though :(

I am still wondering what the ramifications would be if the compiler did apply the const qualifier at all levels of indirection. Would things screw up? Maybe I'll post a question :)
0
 
LVL 1

Expert Comment

by:tapasmondal
ID: 6985894
Here is a appropriate solution which will compile to no error or warning.only u need to do is,call the function as follows:

foo((const int (*)[8])b);
tapas
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6985896
>I am still wondering what the ramifications would
>be if the compiler did apply the const qualifier at
>all levels of indirection.

I don't think that's what the "answer" is talking about. It says that the fact that implicit casting of a pointer to a const pointer is an exception made specifically for that. That exception, however, was only made to the first level of pointers, so it's ok to implicitly cast (int *) to (const int *), but the exception doesn't apply to (int **), which is why one must cast explicitly.


Alexander Maryanovsky.
0
 
LVL 6

Expert Comment

by:zebada
ID: 6986047
What I meant was, what would be the ramification if the exception was extended to all levels of indirection.
i.e. if the exception didn't stop at the top level.

Like you said earlier there is nothing wrong with the code you wrote - there is no ambiguity - there is no confusion so why not let the compiler automatically do the cast for as many nested levels of indirection as necessary.

If there is a reason I would be interested to know it that's all.
0
 
LVL 7

Author Comment

by:Sasha_Mapa
ID: 6986069
Perhaps the answer is somewhere here: http://www.lysator.liu.se/c/rat/title.html :-)

Alexander Maryanovsky.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Goodbye, so long 10 92
libcurl and C++ - Post JSON Data 8 1,078
How to organize data in excel ? 2 107
SQL handling single and double quotes 3 88
Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now