Passing arg from incompatible pointer type

C

Chris Readle

Hi all,

Somewhat new to C and I'm getting the following error from my latest code.

Here's the warning I'm getting:
chris_readle_project3_assignment3.c: In function `main':
chris_readle_project3_assignment3.c:23: warning: passing arg 1 of
`displaySales' from incompatible pointer type

And here is the code in question:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error

So, why am I getting the error and what does it mean? And why do I get
it on the second function call and not the first, which seems exactly
the same, other than being to a different function and not declaring the
parameter as a const?

crr
 
X

xarax

Chris Readle said:
Hi all,

Somewhat new to C and I'm getting the following error from my latest code.

Here's the warning I'm getting:
chris_readle_project3_assignment3.c: In function `main':
chris_readle_project3_assignment3.c:23: warning: passing arg 1 of
`displaySales' from incompatible pointer type

And here is the code in question:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error

So, why am I getting the error and what does it mean? And why do I get
it on the second function call and not the first, which seems exactly
the same, other than being to a different function and not declaring the
parameter as a const?

That's the answer. The parameter is declared const
and the passed value is not a const.
 
C

Chris Readle

xarax said:
Hi all,

Somewhat new to C and I'm getting the following error from my latest code.

Here's the warning I'm getting:
chris_readle_project3_assignment3.c: In function `main':
chris_readle_project3_assignment3.c:23: warning: passing arg 1 of
`displaySales' from incompatible pointer type

And here is the code in question:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error

So, why am I getting the error and what does it mean? And why do I get
it on the second function call and not the first, which seems exactly
the same, other than being to a different function and not declaring the
parameter as a const?


That's the answer. The parameter is declared const
and the passed value is not a const.
Aha, that's what I suspected.

So this is not any kind of hidden thing that's going to come back and
bite me later? I had noticed that everything seems to run just fine,
but I wanted to make sure that this wasn't something that *could* mess
me up later and also that it's not some big style faux pas of which I
was unaware.

crr
 
O

Old Wolf

Chris Readle said:
Hi all,

Somewhat new to C and I'm getting the following error from my latest code.

Here's the warning I'm getting:
chris_readle_project3_assignment3.c: In function `main':
chris_readle_project3_assignment3.c:23: warning: passing arg 1 of
`displaySales' from incompatible pointer type

And here is the code in question:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error

So, why am I getting the error and what does it mean? And why do I get
it on the second function call and not the first, which seems exactly
the same, other than being to a different function and not declaring the
parameter as a const?

You can't "do away with const" over 2 levels of indirection. If they
were 1-D arrays it would have been OK. This is touched on in FAQ 11.10.
There's a good reason for this rule (although it escapes me at the moment).
 
S

S.Tobias

Old Wolf said:
Chris Readle said:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error
You can't "do away with const" over 2 levels of indirection. If they
were 1-D arrays it would have been OK. This is touched on in FAQ 11.10.
There's a good reason for this rule (although it escapes me at the moment).

I think that's an interesting problem.

float *pf;
const float **ppcf = &pf; //unsafe, we are lying to ppcf about pf
const float fdata;
*ppcf = &fdata; //legal, pf is pointed to fdata,
//ppcf "thinks" it is safe
*pf = 13; //disaster!

In general, we were lying as to kind of an object pf points to.


But in the original problem we deal with tables and there is
only *one* level of indirection: `sales' decays to:
float (*)[PRODUCTS]
and is passed to `s', which decays to:
const float (*)[PRODUCTS]
(All items in the table are const, so we might say that the
whole "table object" is const.)
It is like passing `float*' to `const float*', with exception
that in this case `float' is actually `float[PRODUCTS]' (or put
a structure there with PRODUCTS members of type float).

This even looks more like a C++ question.
Can anyone comment on this?
 
D

Dan Pop

In said:
Old Wolf said:
Chris Readle said:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error
You can't "do away with const" over 2 levels of indirection. If they
were 1-D arrays it would have been OK. This is touched on in FAQ 11.10.
There's a good reason for this rule (although it escapes me at the moment).

I think that's an interesting problem.

float *pf;
const float **ppcf = &pf; //unsafe, we are lying to ppcf about pf
const float fdata;
*ppcf = &fdata; //legal, pf is pointed to fdata,
//ppcf "thinks" it is safe
*pf = 13; //disaster!

In general, we were lying as to kind of an object pf points to.

But in the original problem we deal with tables and there is
only *one* level of indirection: `sales' decays to:
float (*)[PRODUCTS]
and is passed to `s', which decays to:
const float (*)[PRODUCTS]
(All items in the table are const, so we might say that the
whole "table object" is const.)
It is like passing `float*' to `const float*', with exception
that in this case `float' is actually `float[PRODUCTS]' (or put
a structure there with PRODUCTS members of type float).

This even looks more like a C++ question.
Can anyone comment on this?

Staying away from "const" helps preserve your sanity (and your hair).

Dan
 
C

Chris Readle

Dan Pop wrote:
-snip-
Staying away from "const" helps preserve your sanity (and your hair).

Dan

Is there another way to simulate least privilege here? This is a
display function that should never modify the data in question, but
*does* need to read it? Or should I just leave it modifiable and make
in clear in comments (not that this code will ever be seen by anyone but
me and my instructor, but I'm speaking more generally here) that to
modify the table in displaySales will bring a slow and painful death?

crr
 
S

S.Tobias

Dan Pop said:
In said:
Old Wolf said:
void inputSales(float s[][PRODUCTS]);
void displaySales(const float s[][PRODUCTS]);

float sales[SALESPEOPLE][PRODUCTS] = {{0}, {0}, {0}, {0}};

inputSales(sales);

displaySales(sales); <---------This one gets the error
[snip]
But in the original problem we deal with tables and there is
only *one* level of indirection: `sales' decays to:
float (*)[PRODUCTS]
and is passed to `s', which decays to:
const float (*)[PRODUCTS]
(All items in the table are const, so we might say that the
whole "table object" is const.)
It is like passing `float*' to `const float*', with exception
that in this case `float' is actually `float[PRODUCTS]' (or put
a structure there with PRODUCTS members of type float).

This even looks more like a C++ question.
Can anyone comment on this?
Staying away from "const" helps preserve your sanity (and your hair).

Thanks for advice, a few years too late, though. As for my hair - soon
there might be no issue :)


I have run OP's code through on-line como: error (warning) in C99
and C90 mode in strict (relaxed) mode, and no diagnostics in C++ mode.
Similarly with gcc/g++.

In C99 Std 6.5.16.1 (Simple assignment): "[...] type pointed to by the
left has all the qualifiers of the type pointed to by the right;",
and argument passing relies on assignment for that matter (6.5.2.2).

In C++ the right expression is converted to the type of left one,
which includes Qualification conversion (4.4), which is slightly
more complicated and more logical than in C IMO.

To sum up: C (unnecessarily) requires all pointed to cv-quals the
same and there's no way without a cast - even if we drop const in
fn parameter, we might want to pass `const float[][]' and run into
same problem - unless we "stay away from const" completely.
(There you are, I've almost come to the same conclusion...)
 
S

S.Tobias

Chris Readle said:
Is there another way to simulate least privilege here? This is a
display function that should never modify the data in question, but
*does* need to read it? Or should I just leave it modifiable and make
in clear in comments (not that this code will ever be seen by anyone but
me and my instructor, but I'm speaking more generally here) that to
modify the table in displaySales will bring a slow and painful death?

My advice would be to keep it as it is, and cast the argument, and
document why the cast was made:
void displaySales(const float s[][PRODUCTS]);
void test()
{
displaySales( (const float (*)[PRODUCTS]) sales); /*cast in const*/
}


My personal way of _documenting_ this is a la C++ (though its meaning and
usage is *completely different*):
#define const_cast(type) (type)
displaySales( const_cast(const float (*)[PRODUCTS]) sales);
But some people don't like it.
 
C

Chris Readle

S.Tobias wrote:

-snip a bunch of my crap-
My advice would be to keep it as it is, and cast the argument, and
document why the cast was made:
void displaySales(const float s[][PRODUCTS]);
void test()
{
displaySales( (const float (*)[PRODUCTS]) sales); /*cast in const*/
}
-snip-

First, thanks for all your help.

Ok, let me see if I understand this, the call:
displaySales((const float (*)[PRODUCTS]) sales); is basically saying:

"Call the function displaySales with the array sales cast as a pointer
to a const of type float." Is that correct?

I may be dense (ok, so no "may" about it ;) ), but what is the
[PRODUCTS] doing inside the cast?

crr
 
S

S.Tobias

Chris Readle said:
Ok, let me see if I understand this, the call:
displaySales((const float (*)[PRODUCTS]) sales); is basically saying:
"Call the function displaySales with the array sales cast as a pointer
to a const of type float." Is that correct?

Err, no...
I may be dense (ok, so no "may" about it ;) ), but what is the
[PRODUCTS] doing inside the cast?

It's a bit long story.

First, learn to read type definitions (this one is a little complex,
but not the most difficult one). There was this nice rule: follow
the parentheses, otherwise first read what is to the right, then
to the left.
const float (*)[PRODUCTS]
1. pointer
2. to length PRODUCTS table
3. of const float values
(in short: "pointer to table of floats")
I'd advise you to look into 6.7.6#3 of C99 Standard and see
a couple of fine examples.

Now, why "[]":
I'm sure you know that ptab2 and ptab3 (pointers to table of int) in:
int (*ptab2)[2];
int (*ptab3)[3];
are incompatible - the pointer arithmetic is different.
(If you don't see why, imagine:
typedef struct {int i0; int i1; } stab2_t;
typedef struct {int i0; int i1; int i2; } stab3_t;
stab2_t *pstab2;
stab3_t *pstab3;
Types stab2_t and stab3_t are different sizes; so are above "inner" tables.)
Compiler has to know the length of "inner" tables in order to know
the proper pointer arithmetic (hence the actual pointer type), but needn't
know the "outer" length. Thats why you can declare:
void inputSales(float s[SALESPEOPLE][PRODUCTS]); /*SALESPEOPLE is ignored*/
or
void inputSales(float s[][PRODUCTS]);
and you can pass arguments:
float sales[SALESPEOPLE][PRODUCTS];
or
float sales2[SALESPEOPLE+20][PRODUCTS];
but you can't pass:
float sales3[SALESPEOPLE][PRODUCTS+1];
^ inner table length is different


Second, why this _form_ of cast:

`sales' is a table:
float sales[][PRODUCTS]; /*length doesn't matter*/
but parameter `s' is:
const float s[][PRODUCTS];

So when passing `sales' to `displaySales' we need to cast it to type like:
const float [][PRODUCTS]; /*table of: length PRODUCTS table of: const float*/
But in a cast operator type name shall be of "scalar type and the operand
shall have scalar type" (6.5.4#2). `sales' in the expression is
converted (decays) to "pointer to table of float" (6.3.2.1#3), so it is
the right (scalar) type here, and its type is:
float (*)[PRODUCTS]
What I did was just add `const' before `float' to convert it to
the desired type.

(Sorry, could have made it shorter, but I don't want
to change all this at this point now.)
 
C

Chris Readle

S.Tobias wrote:

Again, thanks for the help.
It's a bit long story.

First, learn to read type definitions (this one is a little complex,
but not the most difficult one). There was this nice rule: follow
the parentheses, otherwise first read what is to the right, then
to the left.
const float (*)[PRODUCTS]
1. pointer
2. to length PRODUCTS table
3. of const float values
(in short: "pointer to table of floats")
I'd advise you to look into 6.7.6#3 of C99 Standard and see
a couple of fine examples.

Aha, that's what I was missing. I thought it had something to do with
the length of the table, but I wasn't sure how that fit in. I just
finished DLing the Standard, and I'll look up the section you suggest.
-snip-
(Sorry, could have made it shorter, but I don't want
to change all this at this point now.)

No, this was perfect (for me, at least) it really helped me understand
what was going on the cast.

Yet again, thanks for all the help, you're a life saver (or at least a
sanity saver ;) ).

crr
 
D

Dan Pop

In said:
Dan Pop wrote:
-snip-

Is there another way to simulate least privilege here? This is a
display function that should never modify the data in question, but
*does* need to read it? Or should I just leave it modifiable and make
in clear in comments (not that this code will ever be seen by anyone but
me and my instructor, but I'm speaking more generally here) that to
modify the table in displaySales will bring a slow and painful death?

It is already implied by the name and semantics of the function.

Only when a display function *has* to modify its input data is a special
comment necessary, the default assumption is that such a function only
examines its input data.

The only "valid" argument for using const in such cases I have seen
until now is "I am an idiot and I cannot trust myself not to accidentally
alter the data, so I *need* the compiler diagnostics".

Dan
 
O

Old Wolf

The only "valid" argument for using const in such cases I have seen
until now is "I am an idiot and I cannot trust myself not to accidentally
alter the data, so I *need* the compiler diagnostics".

Or a slight variation: "Other developers maintaining this code or using
this library in their own code might be idiots, and I do not want
to waste my time fielding calls and emails from idiots who crash their
program and think it's my fault".
 
C

CBFalconer

Old said:
Or a slight variation: "Other developers maintaining this code
or using this library in their own code might be idiots, and I do
not want to waste my time fielding calls and emails from idiots
who crash their program and think it's my fault".

Or, 3, 6, 12, whatever months from now I or someone else may be
modifying this code without taking the time to read and absorb the
mountainous documentation (if any). It would be nice to have a
mistake exposed at the earliest possible moment.

Believe it or not, computers (even some of those with Microsoft
software) are usually better at remembering and applying minutiae
than you are. I am not too proud to accept help.
 
D

Dan Pop

In said:
Or, 3, 6, 12, whatever months from now I or someone else may be
modifying this code without taking the time to read and absorb the
mountainous documentation (if any).

You don't need to study the documentation, in order to change the code.
Reading the code itself should be enough.
It would be nice to have a
mistake exposed at the earliest possible moment.

If you don't know what you're doing, you have no business touching that
code. There are far too many ways in which you can break it and no
compiler could possibly expose your mistakes.

I have no problems maintaining code I wrote 10 years ago, despite the
complete lack of const in it. And, by engaging my brain, I've been also
maintaining code (more or less badly) written by other people, without
relying on the compiler to find anything else than my own typos.
Believe it or not, computers (even some of those with Microsoft
software) are usually better at remembering and applying minutiae
than you are. I am not too proud to accept help.

Computers can't think for you. If you can't think, either, find a
different kind of job.

Dan
 

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,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top