help on type compatibility?

Discussion in 'C Programming' started by Ark, Feb 24, 2006.

  1. Ark

    Ark Guest

    Hello NG,

    My Lint and my compiler disagree on whether this is valid code:

    typedef int test_t(char *);
    typedef int contest_t(const char *);
    extern contest_t somefunction;
    test_t *mypointer = somefunction;

    I think the assignment is clean in what it does, but who cares? - What's
    the verdict of the standard? (Both C90 and C99 resolutions are greatly
    appreciated.)

    Thank you,
    - Ark
    Ark, Feb 24, 2006
    #1
    1. Advertising

  2. Ark

    aegis Guest

    Ark wrote:
    > Hello NG,
    >
    > My Lint and my compiler disagree on whether this is valid code:
    >
    > typedef int test_t(char *);
    > typedef int contest_t(const char *);
    > extern contest_t somefunction;
    > test_t *mypointer = somefunction;
    >
    > I think the assignment is clean in what it does, but who cares? - What's
    > the verdict of the standard? (Both C90 and C99 resolutions are greatly
    > appreciated.)


    Part of one of the clauses of 3.5.4.3 states:
    [1] "For two function types to be compatible, both
    shall specify compatible return types. Moreover,
    the parameter type lists, if both are present, shall
    agree in the number of parameters and in use of
    the ellipsis terminator; corresponding parameters
    shall have compatible types."

    So we need to ascertain whether or not their parameters
    have compatible type:

    'Is char * compatible with const char *?'

    3.5.4.1 from one of its clauses, states:

    "For two pointer types to be compatible, both
    shall be identically qualified and both shall
    be pointers to compatible types."

    So their compatibility is predicated upon
    whether or not they
    1) point to compatible types
    2) share the same qualifications

    2 does not hold here, and therefore the
    types are not compatible. The implication
    is then that [1] does not hold.

    --
    aegis
    aegis, Feb 24, 2006
    #2
    1. Advertising

  3. Ark

    Ark Guest

    aegis wrote:
    > Ark wrote:
    >
    >>Hello NG,
    >>
    >>My Lint and my compiler disagree on whether this is valid code:
    >>
    >>typedef int test_t(char *);
    >>typedef int contest_t(const char *);
    >>extern contest_t somefunction;
    >>test_t *mypointer = somefunction;
    >>
    >>I think the assignment is clean in what it does, but who cares? - What's
    >>the verdict of the standard? (Both C90 and C99 resolutions are greatly
    >>appreciated.)

    >
    >
    > Part of one of the clauses of 3.5.4.3 states:
    > [1] "For two function types to be compatible, both
    > shall specify compatible return types. Moreover,
    > the parameter type lists, if both are present, shall
    > agree in the number of parameters and in use of
    > the ellipsis terminator; corresponding parameters
    > shall have compatible types."
    >
    > So we need to ascertain whether or not their parameters
    > have compatible type:
    >
    > 'Is char * compatible with const char *?'
    >
    > 3.5.4.1 from one of its clauses, states:
    >
    > "For two pointer types to be compatible, both
    > shall be identically qualified and both shall
    > be pointers to compatible types."
    >
    > So their compatibility is predicated upon
    > whether or not they
    > 1) point to compatible types
    > 2) share the same qualifications
    >
    > 2 does not hold here, and therefore the
    > types are not compatible. The implication
    > is then that [1] does not hold.
    >
    > --
    > aegis
    >

    Thank you, aegis.
    But...
    Is it indeed that char * is not compatible with const char * ?
    char * is unqualified pointer to char; const char * is unqualified
    pointer to const char. So the question reduces to whether char is
    compatible with const char, and I think it is... After all, we routinely
    write
    char c;
    const char cc;
    char *p;
    const char *cp;
    ..............
    c = cc;
    cp = p;
    I beg for further clarification...
    Thank you,
    Ark
    Ark, Feb 24, 2006
    #3
  4. Ark

    Robin Haigh Guest

    "Ark" <> wrote in message
    news:...
    > Hello NG,
    >
    > My Lint and my compiler disagree on whether this is valid code:
    >
    > typedef int test_t(char *);
    > typedef int contest_t(const char *);
    > extern contest_t somefunction;
    > test_t *mypointer = somefunction;
    >
    > I think the assignment is clean in what it does, but who cares? - What's
    > the verdict of the standard? (Both C90 and C99 resolutions are greatly
    > appreciated.)


    The assignment is legal because it's portable to convert a function pointer
    to a different function pointer type and back again. (This can avoid the
    need to use unions of function pointer types, which would be pointlessly
    clumsy.)

    But it's well worth a warning at this point, because no warning can be given
    later if you then call the function through the pointer of the wrong type,
    and that would produce undefined behaviour.

    The problem is that the caller and the callee must agree implicitly on all
    the details of how the function call is actually set up. The compiler makes
    its own rules about that, and it's allowed to refer to the types of the
    arguments, including qualifiers, if there's a prototype. So calling through
    the wrong prototype can produce a mismatch in the calling sequence.

    In this case it's likely that the undefined behaviour produced is to do the
    right thing on all implementations, unless somebody knows different...

    --
    RSH
    Robin Haigh, Feb 24, 2006
    #4
  5. Ark

    pete Guest

    Ark wrote:

    > char * is unqualified pointer to char; const char * is unqualified
    > pointer to const char.


    No.

    N869
    6.2.5 Types
    [#26]
    Each
    unqualified type has several qualified versions of its
    type, corresponding to the combinations of one, two, or
    all three of the const, volatile, and restrict qualifiers.

    --
    pete
    pete, Feb 24, 2006
    #5
  6. Ark

    mark Guest

    pete wrote:
    > Ark wrote:
    >
    > > char * is unqualified pointer to char; const char * is unqualified
    > > pointer to const char.

    >
    > No.


    Yes.
    mark, Feb 24, 2006
    #6
  7. Ark

    Chris Torek Guest

    In article <>
    Ark <> wrote:
    >Is it indeed that char * is not compatible with const char *?


    Yes, it is indeed not compatible.

    >[yet] we routinely write
    >char *p;
    >const char *cp;
    >.............
    >cp = p;
    >I beg for further clarification...


    There is a special rule for assignment (including the implied
    assignment from prototyped function calls) that relaxes the
    constraints, so that you can do "cp = p", but not "p = cp".

    This special rule does *not* apply to other cases, so:

    char **pp;
    ...
    pp = &cp;

    requires a diagnostic.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Feb 24, 2006
    #7
  8. Ark

    Chris Torek Guest

    >"Ark" <> wrote in message
    >news:...
    >> My Lint and my compiler disagree on whether this is valid code:
    >>
    >> typedef int test_t(char *);
    >> typedef int contest_t(const char *);
    >> extern contest_t somefunction;
    >> test_t *mypointer = somefunction;


    In article <dtmhjq$1fs$>
    Robin Haigh <> wrote:
    >The assignment is legal because ...


    The assignment requires a diagnostic. GCC (some versions anyway)
    just gets this wrong.

    I think you are thinking of the version with casts:

    test_t *mypointer = (test_t *)somefunction;

    which does not require a diagnostic.

    >The problem is that the caller and the callee must agree implicitly on all
    >the details of how the function call is actually set up.


    This, however, is correct.

    The Standard has some wording that implies (or perhaps even "requires"
    if you believe the footnotes, but the footnotes are "non-normative",
    meaning an Evil Implementor can violate them without breaking the
    rules) ... er, where was I? Oh yes: qualified and unqualified
    variants of types are *supposed* to have the same underlying
    representations, so one might simply assume that test_t and contest_t
    are effectively interchangeable, and get away with it. It is quite
    unlikely to break. Still, it is best not to skate on the thin ice.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Feb 24, 2006
    #8
  9. Ark

    pete Guest

    mark wrote:
    >
    > pete wrote:
    > > Ark wrote:
    > >
    > > > char * is unqualified pointer to char; const char * is unqualified
    > > > pointer to const char.

    > >
    > > No.

    >
    > Yes.


    Idiot.

    > > N869
    > > 6.2.5 Types
    > > [#26]
    > > Each
    > > unqualified type has several qualified versions of its
    > > type, corresponding to the combinations of one, two, or
    > > all three of the const, volatile, and restrict qualifiers.


    --
    pete
    pete, Feb 24, 2006
    #9
  10. Ark

    Jordan Abel Guest

    On 2006-02-24, Chris Torek <> wrote:
    >>"Ark" <> wrote in message
    >>news:...
    >>> My Lint and my compiler disagree on whether this is valid code:
    >>>
    >>> typedef int test_t(char *);
    >>> typedef int contest_t(const char *);
    >>> extern contest_t somefunction;
    >>> test_t *mypointer = somefunction;

    >
    > In article <dtmhjq$1fs$>
    > Robin Haigh <> wrote:
    >>The assignment is legal because ...

    >
    > The assignment requires a diagnostic. GCC (some versions anyway)
    > just gets this wrong.
    >
    > I think you are thinking of the version with casts:
    >
    > test_t *mypointer = (test_t *)somefunction;
    >
    > which does not require a diagnostic.
    >
    >>The problem is that the caller and the callee must agree implicitly on all
    >>the details of how the function call is actually set up.

    >
    > This, however, is correct.
    >
    > The Standard has some wording that implies (or perhaps even "requires"
    > if you believe the footnotes, but the footnotes are "non-normative",
    > meaning an Evil Implementor can violate them without breaking the
    > rules)


    Even if the footnote is prescribing an interpretation of normative text,
    rather than providing new rules?

    > ... er, where was I? Oh yes: qualified and unqualified variants of
    > types are *supposed* to have the same underlying representations, so
    > one might simply assume that test_t and contest_t are effectively
    > interchangeable, and get away with it. It is quite unlikely to break.
    > Still, it is best not to skate on the thin ice.
    Jordan Abel, Feb 24, 2006
    #10
  11. Ark

    pete Guest

    pete wrote:
    >
    > mark wrote:
    > >
    > > pete wrote:
    > > > Ark wrote:
    > > >
    > > > > char * is unqualified pointer to char; const char * is unqualified
    > > > > pointer to const char.
    > > >
    > > > No.

    > >
    > > Yes.

    >
    > Idiot.


    After further consideration, I take it back.
    Sorry.

    --
    pete
    pete, Feb 24, 2006
    #11
  12. Ark

    Guest

    aegis wrote:
    ....
    > 'Is char * compatible with const char *?'
    >
    > 3.5.4.1 from one of its clauses, states:
    >
    > "For two pointer types to be compatible, both
    > shall be identically qualified and both shall
    > be pointers to compatible types."
    >
    > So their compatibility is predicated upon
    > whether or not they
    > 1) point to compatible types
    > 2) share the same qualifications
    >
    > 2 does not hold here, and therefore the
    > types are not compatible.


    I don't follow that: neither pointer type is qualified, so item [2]
    holds. Only the pointed-at types are differently qualified. The pointer
    types themselves are both unqualified.

    > The implication is then that [1] does not hold.


    I don't follow that implication. You're right that [1] doesn't hold.
    However, that's because 6.7.3p9 requires the two types to have the same
    qualification in order to be compatible, and "char" has different
    qualification than "const char". It has nothing to do with the fact
    that 3.5.4.1 requires the pointer types themselves to be identically
    qualified.
    , Feb 24, 2006
    #12
  13. Chris Torek wrote:
    > ... so that you can do "cp = p", but not "p = cp".


    Of course in practice you can accomplish the effect by
    using a cast. At least that documents that something
    unusual (and perhaps incorrect) is going on.
    Douglas A. Gwyn, Feb 25, 2006
    #13
  14. Chris Torek wrote:
    > ... the footnotes are "non-normative",
    > meaning an Evil Implementor can violate them without breaking the
    > rules) ...


    No that's not what it means. The footnotes (and examples)
    are not meant to impose any additional requirements, but
    they can and do clarify what is meant by otherwise puzzling
    requirements in the normative portion of the text.
    Douglas A. Gwyn, Feb 25, 2006
    #14
  15. "Douglas A. Gwyn" <> writes:
    > Chris Torek wrote:
    >> ... the footnotes are "non-normative",
    >> meaning an Evil Implementor can violate them without breaking the
    >> rules) ...

    >
    > No that's not what it means. The footnotes (and examples)
    > are not meant to impose any additional requirements, but
    > they can and do clarify what is meant by otherwise puzzling
    > requirements in the normative portion of the text.


    But they do not always do so perfectly.

    For example, 6.2.5p26 says:

    A pointer to void shall have the same representation and alignment
    requirements as a pointer to a character type.

    and a footnote says:

    The same representation and alignment requirements are meant to
    imply interchangeability as arguments to functions, return values
    from functions, and members of unions.

    Without that footnote, an implementation that passed void* and char*
    arguments in different registers (as some real implementations do for
    integer and floating-point arguments) could be conforming; the types
    would still have the same representation and alignment requirements.

    There would be little reason (that I can think of) for an
    implementation to pass char* and void* differently, but as a
    programmer I wouldn't be able to assume that they weren't if I wanted
    my code to be portable.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Feb 25, 2006
    #15
  16. Ark

    Guest

    Douglas A. Gwyn wrote:
    > Chris Torek wrote:
    > > ... the footnotes are "non-normative",
    > > meaning an Evil Implementor can violate them without breaking the
    > > rules) ...

    >
    > No that's not what it means. The footnotes (and examples)
    > are not meant to impose any additional requirements,


    The point is, that not only are they not meant to impose any additional
    requirements, they CAN"T impose any additional requirements. A footnote
    can guide us to the correct interpretation of the requirements, but if
    a footnote claims that something is true which cannot be derived from
    the normative text, that claim is simply false, and can therefore be
    ignored.
    , Feb 25, 2006
    #16
  17. Ark

    WaterWalk Guest

    I'm sorry, but what does "typedef int test_t(char *)" mean?

    int test_t(char *); //This is a function prototype
    typedef int (*test_t)(char *); //This is a fuction pointer typedef

    But,
    typedef int test_t(char *); // I don't know what it is.
    WaterWalk, Feb 25, 2006
    #17
  18. Ark

    pete Guest

    WaterWalk wrote:
    >
    > I'm sorry, but what does "typedef int test_t(char *)" mean?
    >
    > int test_t(char *); //This is a function prototype


    When you have a declaration
    with a primary expression identifier,
    and you write "typedef" in front of it,
    what was the identifier in the declaration,
    becomes a name for the type that it had.

    That typedef is for a function type.

    /* BEGIN new.c */

    #include <stdio.h>

    typedef int test_t(char *);

    test_t test1, test2;

    int main(void)
    {
    test1("Hello");
    test1("World");
    return 0;
    }

    int test1(char *a)
    {
    return puts(a);
    }

    int test2(char *a)
    {
    return puts(a);
    }

    /* END new.c */

    --
    pete
    pete, Feb 25, 2006
    #18
  19. Ark

    pete Guest

    pete wrote:

    > typedef int test_t(char *);
    >
    > test_t test1, test2;
    >
    > int main(void)
    > {
    > test1("Hello");
    > test1("World");


    I intended that last line to be test2("World")
    but it doesn't make much difference.

    --
    pete
    pete, Feb 25, 2006
    #19
  20. On Fri, 24 Feb 2006 18:48:46 +0000, Chris Torek wrote:

    > In article <> Ark
    > <> wrote:
    >>Is it indeed that char * is not compatible with const char *?

    >
    > Yes, it is indeed not compatible.
    >
    >>[yet] we routinely write
    >>char *p;
    >>const char *cp;
    >>.............
    >>cp = p;
    >>I beg for further clarification...

    >
    > There is a special rule for assignment (including the implied assignment
    > from prototyped function calls) that relaxes the constraints, so that you
    > can do "cp = p", but not "p = cp".
    >
    > This special rule does *not* apply to other cases, so:
    >
    > char **pp;
    > ...
    > pp = &cp;
    >
    > requires a diagnostic.


    I some ways the more surprising example is that:

    const char * const *pcp;
    pcp = pp;

    also requires a diagnostic. Surprising because this way round no
    "const"ness is being lost.

    --
    Ben.
    Ben Bacarisse, Feb 25, 2006
    #20
    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. John C. Bollinger

    Bounded wildcards and type compatibility

    John C. Bollinger, Jan 4, 2006, in forum: Java
    Replies:
    6
    Views:
    369
    John C. Bollinger
    Jan 4, 2006
  2. heyo
    Replies:
    3
    Views:
    887
    Dan Pop
    Apr 1, 2004
  3. pete
    Replies:
    4
    Views:
    784
    Dan Pop
    Apr 2, 2004
  4. Replies:
    0
    Views:
    272
  5. \Dandy\ Randy

    File type compatibility issue with Perl

    \Dandy\ Randy, Jul 28, 2003, in forum: Perl Misc
    Replies:
    3
    Views:
    93
    Garry Short
    Jul 28, 2003
Loading...

Share This Page