Passing arg from incompatible pointer type

Discussion in 'C Programming' started by Chris Readle, Jun 20, 2004.

  1. Chris Readle

    Chris Readle Guest

    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
    Chris Readle, Jun 20, 2004
    #1
    1. Advertising

  2. Chris Readle

    xarax Guest

    "Chris Readle" <> wrote in message
    news:qMnBc.3235$DQ4.1776@fed1read05...
    > 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.
    xarax, Jun 21, 2004
    #2
    1. Advertising

  3. Chris Readle

    Chris Readle Guest

    xarax wrote:

    > "Chris Readle" <> wrote in message
    > news:qMnBc.3235$DQ4.1776@fed1read05...
    >
    >>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
    Chris Readle, Jun 21, 2004
    #3
  4. Chris Readle

    Old Wolf Guest

    Chris Readle <> wrote:
    > 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).
    Old Wolf, Jun 21, 2004
    #4
  5. Chris Readle

    S.Tobias Guest

    Old Wolf <> wrote:
    > Chris Readle <> wrote:
    > > 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?

    --
    Stan Tobias
    S.Tobias, Jun 21, 2004
    #5
  6. Chris Readle

    Dan Pop Guest

    In <> "S.Tobias" <> writes:

    >Old Wolf <> wrote:
    >> Chris Readle <> wrote:
    >> > 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
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Jun 21, 2004
    #6
  7. Chris Readle

    Chris Readle Guest

    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
    Chris Readle, Jun 21, 2004
    #7
  8. Chris Readle

    S.Tobias Guest

    Dan Pop <> wrote:
    > In <> "S.Tobias" <> writes:
    > >Old Wolf <> wrote:
    > >> Chris Readle <> wrote:
    > >> > 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...)

    --
    Stan Tobias
    S.Tobias, Jun 21, 2004
    #8
  9. Chris Readle

    S.Tobias Guest

    Chris Readle <> wrote:
    > 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.

    --
    Stan Tobias
    S.Tobias, Jun 21, 2004
    #9
  10. Chris Readle

    Chris Readle Guest

    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
    Chris Readle, Jun 21, 2004
    #10
  11. Chris Readle

    S.Tobias Guest

    Chris Readle <> wrote:

    > 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.)

    --
    Stan Tobias
    S.Tobias, Jun 22, 2004
    #11
  12. Chris Readle

    Chris Readle Guest

    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
    Chris Readle, Jun 22, 2004
    #12
  13. Chris Readle

    Dan Pop Guest

    In <seGBc.3856$DQ4.470@fed1read05> Chris Readle <> writes:

    >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?


    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
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Jun 22, 2004
    #13
  14. Chris Readle

    Old Wolf Guest

    (Dan Pop) wrote:
    >
    > 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".
    Old Wolf, Jun 23, 2004
    #14
  15. Chris Readle

    CBFalconer Guest

    Old Wolf wrote:
    > (Dan Pop) wrote:
    >>
    >> 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".


    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.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
    CBFalconer, Jun 23, 2004
    #15
  16. Chris Readle

    Dan Pop Guest

    In <> CBFalconer <> writes:

    >Old Wolf wrote:
    >> (Dan Pop) wrote:
    >>>
    >>> 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".

    >
    >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
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
    Dan Pop, Jun 24, 2004
    #16
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DuckMan
    Replies:
    0
    Views:
    389
    DuckMan
    Mar 9, 2007
  2. n00m
    Replies:
    5
    Views:
    380
  3. DFouton
    Replies:
    1
    Views:
    959
    DFouton
    Nov 14, 2010
  4. Replies:
    7
    Views:
    158
  5. Replies:
    21
    Views:
    256
    Barry Schwarz
    Mar 5, 2014
Loading...

Share This Page