const array of const pointers as a parameter

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Spoon

    const array of const pointers as a parameter

    Hello,

    I don't understand why gcc barks at me in this situation:

    $ cat foo.c
    extern void func(const int * const list[], int nent);

    int main(void)
    {
    int *p[5];
    func(p, 5);
    return 0;
    }

    $ gcc -Wall -std=c89 -c foo.c
    foo.c: In function `main':
    foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type

    AFAIU, func promises not to change the values pointed to by the pointers
    in the array (i.e. *list[2] = 666 is illegal) AND not to change the
    pointers themselves (i.e. list[2] = NULL is also illegal).

    I don't understand what the compiler dislikes about p.

    Could someone enlighten me?
  • Darko

    #2
    Re: const array of const pointers as a parameter

    Hm. I myself too had trouble with consts pretty much the same way you
    do now. As far as I can recall, multiple consts in the same expression
    are not allowed by ANSI. However, lots of things seem not to be allowed
    by ANSI and yet are quite normal in practice.

    Anyway, my humble opinion is that you should try adding another const
    at the and of your "list" expression, like in: const int * const * list
    const. That way you declare list to be constant, too, which is true
    because what you've got down there is a static array, which is actually
    a constant pointer to another pointer.

    I would try it myself but I don't have Linux here at work.

    Bye,

    Darko

    Spoon wrote:
    Hello,
    >
    I don't understand why gcc barks at me in this situation:
    >
    $ cat foo.c
    extern void func(const int * const list[], int nent);
    >
    int main(void)
    {
    int *p[5];
    func(p, 5);
    return 0;
    }
    >
    $ gcc -Wall -std=c89 -c foo.c
    foo.c: In function `main':
    foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type
    >
    AFAIU, func promises not to change the values pointed to by the pointers
    in the array (i.e. *list[2] = 666 is illegal) AND not to change the
    pointers themselves (i.e. list[2] = NULL is also illegal).
    >
    I don't understand what the compiler dislikes about p.
    >
    Could someone enlighten me?

    Comment

    • arne

      #3
      Re: const array of const pointers as a parameter

      Spoon schrieb:
      Hello,
      >
      I don't understand why gcc barks at me in this situation:
      >
      $ cat foo.c
      extern void func(const int * const list[], int nent);
      >
      int main(void)
      {
      int *p[5];
      func(p, 5);
      return 0;
      }
      >
      $ gcc -Wall -std=c89 -c foo.c
      foo.c: In function `main':
      foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type
      >
      AFAIU, func promises not to change the values pointed to by the pointers
      in the array (i.e. *list[2] = 666 is illegal) AND not to change the
      pointers themselves (i.e. list[2] = NULL is also illegal).
      >
      I don't understand what the compiler dislikes about p.
      >
      Could someone enlighten me?
      What about changing

      int *p[5];

      to

      const int *p[5]; ?


      The function expects an array of const pointers to const ints, but you
      pass an array of pointers to ints.

      Comment

      • Andrey Tarasevich

        #4
        Re: const array of const pointers as a parameter

        Spoon wrote:
        Hello,
        >
        I don't understand why gcc barks at me in this situation:
        >
        $ cat foo.c
        extern void func(const int * const list[], int nent);
        >
        int main(void)
        {
        int *p[5];
        func(p, 5);
        return 0;
        }
        >
        $ gcc -Wall -std=c89 -c foo.c
        foo.c: In function `main':
        foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type
        >
        AFAIU, func promises not to change the values pointed to by the pointers
        in the array (i.e. *list[2] = 666 is illegal) AND not to change the
        pointers themselves (i.e. list[2] = NULL is also illegal).
        >
        I don't understand what the compiler dislikes about p.
        ...
        The function parameter declaration is equivalent to 'const int* const* list'.
        The type of actual argument (array 'p') decays to 'int**'. In other words, you
        are trying to initialize an object of type 'const int* const*' with a value of
        type 'int**'. This is not allowed by const-correctness rules of C language. The
        culprit is the first 'const' from the left. C language allows you to "add" a
        'const' at the first level of indirection, but not at any deeper level of
        indirection. I.e. it is OK to convert 'int**' to 'int* const*', but it is not OK
        to convert it to either 'const int**' or 'const int* const*'.

        The rationale behind this is described in the following C++ (sic) FAQ entry



        This is a C++ FAQ entry, but it does explain the issue very well. (There's also
        a similar example in C99 standard.) However, C++ language adopted a more
        elaborate behavior in this case and, as a result, C++ actually _allows_ the
        'int**' to 'const int* const*' conversion (still disallowing the conversion to
        'const int**'). C language decided to stay with a more primitive/simplified
        specification, meaning that 'int**' to 'const int* const*' conversion is
        outlawed in C, even though it's harmless from the const-correctness point of view.

        --
        Best regards,
        Andrey Tarasevich

        Comment

        • A. Bolmarcich

          #5
          Re: const array of const pointers as a parameter

          On 2006-10-18, Spoon <devnull@localh ost.comwrote:
          Hello,
          >
          I don't understand why gcc barks at me in this situation:
          >
          $ cat foo.c
          extern void func(const int * const list[], int nent);
          >
          int main(void)
          {
          int *p[5];
          func(p, 5);
          return 0;
          }
          >
          $ gcc -Wall -std=c89 -c foo.c
          foo.c: In function `main':
          foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type
          >
          AFAIU, func promises not to change the values pointed to by the pointers
          in the array (i.e. *list[2] = 666 is illegal) AND not to change the
          pointers themselves (i.e. list[2] = NULL is also illegal).
          >
          I don't understand what the compiler dislikes about p.
          >
          Could someone enlighten me?
          The assignment constraint in the C89 specification being used in this
          case is

          both operands are pointers to qualified or unqualified types verisons
          of compatible types, and the type pointed to by the left has all the
          qualifiers as the type pointed to by the right

          Also, according th the C89 specification

          For two qualified types to be compatible, both shall have the identical
          qualified versions of a compatible type

          The argument type is pointerTo-pointerTo-int and the parameter type is
          pointerTo-pointerTo-const-int. According to the C89 specification
          a pointerTo-int is not compatible with pointerTo-const-int because they
          are not identically qualified.

          The assignment constraint allows the parameter to have additional
          "top-level" pointer qualifiers that the argument does not have. This
          allows a (* int) argument to be assigned to a (const * int) parameter.
          However, that constraint does not apply to "inner-level" pointers which
          need to be identically qualified.

          Comment

          • John Bode

            #6
            Re: const array of const pointers as a parameter


            Spoon wrote:
            Hello,
            >
            I don't understand why gcc barks at me in this situation:
            >
            $ cat foo.c
            extern void func(const int * const list[], int nent);
            >
            int main(void)
            {
            int *p[5];
            This is not an array of constant pointers. That's why you're getting
            barked at.

            If you declare it as

            int const *p[5];

            the code should compile (it does for me, anyway). Whether that's what
            you really *want* to do is an open question (I suspect it isn't).
            func(p, 5);
            return 0;
            }
            >
            $ gcc -Wall -std=c89 -c foo.c
            foo.c: In function `main':
            foo.c:6: warning: passing arg 1 of `func' from incompatible pointer type
            >
            AFAIU, func promises not to change the values pointed to by the pointers
            in the array (i.e. *list[2] = 666 is illegal) AND not to change the
            pointers themselves (i.e. list[2] = NULL is also illegal).
            >
            I don't understand what the compiler dislikes about p.
            >
            Could someone enlighten me?

            Comment

            • lawrence.jones@ugs.com

              #7
              Re: const array of const pointers as a parameter

              Andrey Tarasevich <andreytarasevi ch@hotmail.comw rote:
              >
              This is a C++ FAQ entry, but it does explain the issue very well. (There's also
              a similar example in C99 standard.) However, C++ language adopted a more
              elaborate behavior in this case and, as a result, C++ actually _allows_ the
              'int**' to 'const int* const*' conversion (still disallowing the conversion to
              'const int**'). C language decided to stay with a more primitive/simplified
              specification, meaning that 'int**' to 'const int* const*' conversion is
              outlawed in C, even though it's harmless from the const-correctness point of view.
              In particular, the original C rules were developed before the C++ rules
              had been worked out. Once they were, the way C++ describes the common
              language is sufficiently different from the way C describes it that the
              rules could not just be lifted verbatim but would have to be rewritten
              (in particular, I seem to recall some unrelated handwaving in the C++
              standard that happens to make arrays work out right that does not exist
              in the C standard). Also, C added the restrict type qualifier, which
              complicates the rules since it does not work the same way as const and
              volatile do. So far as I know, no one has worked out the rules with
              restrict included.

              -Larry Jones

              Hey Doc, for 10 bucks I'll make sure you see those kids in the
              waiting room again real soon! -- Calvin

              Comment

              Working...