Help on 6.5.2.2p6 (function calls)

Discussion in 'C Programming' started by Francis Moreau, Jun 2, 2010.

  1. Hello,

    I think I've mostly understood this section but the last part is still
    obscure for me.

    Here is what it says:

    If the function is defined with a type that does not include a
    prototype,
    and the types of the arguments after promotion are not compatible
    with those of the parameters after promotion, the behavior is
    undefined, except for the following cases:

    [...]

    I fail to understand "parameters after promotion". I thought that
    promotions were applied to arguments only (not parameters).

    So here is a definition without prototype:

    void foo(a, b, c) { return; }

    I thought that type of parameters default to int, so there's no need
    for promotions here.

    Could anybody shed some light here ?

    Thanks
    Francis Moreau, Jun 2, 2010
    #1
    1. Advertising

  2. Francis Moreau

    Dann Corbit Guest

    In article <d305fbc1-2ebf-4205-9fa6-65a6c445f304
    @e28g2000vbd.googlegroups.com>, says...
    >
    > Hello,
    >
    > I think I've mostly understood this section but the last part is still
    > obscure for me.
    >
    > Here is what it says:
    >
    > If the function is defined with a type that does not include a
    > prototype,
    > and the types of the arguments after promotion are not compatible
    > with those of the parameters after promotion, the behavior is
    > undefined, except for the following cases:
    >
    > [...]
    >
    > I fail to understand "parameters after promotion". I thought that
    > promotions were applied to arguments only (not parameters).
    >
    > So here is a definition without prototype:
    >
    > void foo(a, b, c) { return; }
    >
    > I thought that type of parameters default to int, so there's no need
    > for promotions here.
    >
    > Could anybody shed some light here ?


    Consider:

    #include <stdio.h>

    float f = 3.14159;

    printf("%g\n", f);

    The type of f is float, but it will be promoted to double.

    As an example, consider this question from the C-FAQ:

    12.9: Someone told me it was wrong to use %lf with printf(). How can
    printf() use %f for type double, if scanf() requires %lf?

    A: It's true that printf's %f specifier works with both float and
    double arguments. Due to the "default argument promotions"
    (which apply in variable-length argument lists such as printf's,
    whether or not prototypes are in scope), values of type float
    are promoted to double, and printf() therefore sees only
    doubles. (printf() does accept %Lf, for long double.)
    See also questions 12.13 and 15.2.

    References: K&R1 Sec. 7.3 pp. 145-47, Sec. 7.4 pp. 147-50; K&R2
    Sec. 7.2 pp. 153-44, Sec. 7.4 pp. 157-59; ISO Sec. 7.9.6.1,
    Sec. 7.9.6.2; H&S Sec. 15.8 pp. 357-64, Sec. 15.11 pp. 366-78;
    CT&P Sec. A.1 pp. 121-33.

    and similarly:

    15.2: How can %f be used for both float and double arguments in
    printf()? Aren't they different types?

    A: In the variable-length part of a variable-length argument list,
    the "default argument promotions" apply: types char and
    short int are promoted to int, and float is promoted to double.
    (These are the same promotions that apply to function calls
    without a prototype in scope, also known as "old style" function
    calls; see question 11.3.) Therefore, printf's %f format always
    sees a double. (Similarly, %c always sees an int, as does %hd.)
    See also questions 12.9 and 12.13.

    References: ISO Sec. 6.3.2.2; H&S Sec. 6.3.5 p. 177, Sec. 9.4
    pp. 272-3.

    And even a bit more esoteric:

    15.10: I have a varargs function which accepts a float parameter. Why
    isn't

    va_arg(argp, float)

    working?

    A: In the variable-length part of variable-length argument lists,
    the old "default argument promotions" apply: arguments of type
    float are always promoted (widened) to type double, and types
    char and short int are promoted to int. Therefore, it is never
    correct to invoke va_arg(argp, float); instead you should always
    use va_arg(argp, double). Similarly, use va_arg(argp, int) to
    retrieve arguments which were originally char, short, or int.
    (For analogous reasons, the last "fixed" argument, as handed to
    va_start(), should not be widenable, either.) See also
    questions 11.3 and 15.2.

    References: ISO Sec. 6.3.2.2; Rationale Sec. 4.8.1.2; H&S
    Sec. 11.4 p. 297.
    Dann Corbit, Jun 2, 2010
    #2
    1. Advertising

  3. Francis Moreau

    Dann Corbit Guest

    In article <-september.org>,
    says...
    >
    > In article <d305fbc1-2ebf-4205-9fa6-65a6c445f304
    > @e28g2000vbd.googlegroups.com>, says...
    > >
    > > Hello,
    > >
    > > I think I've mostly understood this section but the last part is still
    > > obscure for me.
    > >
    > > Here is what it says:
    > >
    > > If the function is defined with a type that does not include a
    > > prototype,
    > > and the types of the arguments after promotion are not compatible
    > > with those of the parameters after promotion, the behavior is
    > > undefined, except for the following cases:
    > >
    > > [...]
    > >
    > > I fail to understand "parameters after promotion". I thought that
    > > promotions were applied to arguments only (not parameters).
    > >
    > > So here is a definition without prototype:
    > >
    > > void foo(a, b, c) { return; }
    > >
    > > I thought that type of parameters default to int, so there's no need
    > > for promotions here.
    > >
    > > Could anybody shed some light here ?

    >


    Also pertinent:

    11.3: My ANSI compiler complains about a mismatch when it sees

    extern int func(float);

    int func(x)
    float x;
    { ...

    A: You have mixed the new-style prototype declaration
    "extern int func(float);" with the old-style definition
    "int func(x) float x;". It is usually possible to mix the two
    styles (see question 11.4), but not in this case.

    Old C (and ANSI C, in the absence of prototypes, and in
    variable-length argument lists; see question 15.2) "widens"
    certain arguments when they are passed to functions. floats
    are promoted to double, and characters and short integers are
    promoted to int. (For old-style function definitions, the
    values are automatically converted back to the corresponding
    narrower types within the body of the called function, if they
    are declared that way there.)

    This problem can be fixed either by using new-style syntax
    consistently in the definition:

    int func(float x) { ... }

    or by changing the new-style prototype declaration to match the
    old-style definition:

    extern int func(double);

    (In this case, it would be clearest to change the old-style
    definition to use double as well, if possible.)

    It is arguably much safer to avoid "narrow" (char, short int,
    and float) function arguments and return types altogether.

    See also question 1.25.

    References: K&R1 Sec. A7.1 p. 186; K&R2 Sec. A7.3.2 p. 202; ISO
    Sec. 6.3.2.2, Sec. 6.5.4.3; Rationale Sec. 3.3.2.2,
    Sec. 3.5.4.3; H&S Sec. 9.2 pp. 265-7, Sec. 9.4 pp. 272-3.
    Dann Corbit, Jun 2, 2010
    #3
  4. On Jun 2, 10:40 am, Francis Moreau <> wrote:
    > Hello,
    >
    > I think I've mostly understood this section but the last part is still
    > obscure for me.
    >
    > Here is what it says:
    >
    >   If the function is defined with a type that does not include a
    > prototype,
    >   and the types of the arguments after promotion are not compatible
    >   with those of the parameters after promotion, the behavior is
    >   undefined, except for the following cases:
    >
    >   [...]
    >
    > I fail to understand "parameters after promotion". I thought that
    > promotions were applied to arguments only (not parameters).
    >
    > So here is a definition without prototype:
    >
    >    void foo(a, b, c) { return; }
    >
    > I thought that type of parameters default to int, so there's no need
    > for promotions here.
    >
    > Could anybody shed some light here ?


    Well I think my misunderstanding is coming from the fact that I don't
    know the "old style" function definition.

    Can anybody gives me some pointers about it ?

    Thanks
    Francis Moreau, Jun 2, 2010
    #4
  5. Francis Moreau

    Dann Corbit Guest

    In article <cc0f5cf7-2105-4616-b0d8-98d94592f827
    @a16g2000vbr.googlegroups.com>, says...
    >
    > On Jun 2, 10:40 am, Francis Moreau <> wrote:
    > > Hello,
    > >
    > > I think I've mostly understood this section but the last part is still
    > > obscure for me.
    > >
    > > Here is what it says:
    > >
    > >   If the function is defined with a type that does not include a
    > > prototype,
    > >   and the types of the arguments after promotion are not compatible
    > >   with those of the parameters after promotion, the behavior is
    > >   undefined, except for the following cases:
    > >
    > >   [...]
    > >
    > > I fail to understand "parameters after promotion". I thought that
    > > promotions were applied to arguments only (not parameters).
    > >
    > > So here is a definition without prototype:
    > >
    > >    void foo(a, b, c) { return; }
    > >
    > > I thought that type of parameters default to int, so there's no need
    > > for promotions here.
    > >
    > > Could anybody shed some light here ?

    >
    > Well I think my misunderstanding is coming from the fact that I don't
    > know the "old style" function definition.
    >
    > Can anybody gives me some pointers about it ?


    If anyone is still using a C compiler that does not at least adhere to
    the first ANSI/ISO standard, then time to upgrade.

    Anyway, pre-ANSI C looked like this (example from ZLIB):

    /*
    ====================================================================
    */
    int ZEXPORT compress (dest, destLen, source, sourceLen)
    Bytef *dest;
    uLongf *destLen;
    const Bytef *source;
    uLong sourceLen;
    {
    return compress2(dest, destLen, source, sourceLen,
    Z_DEFAULT_COMPRESSION);
    }

    ZEXPORT is a macro that will vary by compiler used to make the symbol
    public to end-users.

    You will notice in the function declaration:
    int ZEXPORT compress (dest, destLen, source, sourceLen)

    there are no types to be seen. Those are published right below the
    function declaration but before the function body.
    In this case, we have a bunch of types that have been defined via
    typedef.

    Generally speaking, I take monstrosities such as this and feed them to
    protoize so that I get something sensible to work with.
    Unfortunately, protoize does not always work.
    Dann Corbit, Jun 2, 2010
    #5
    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. Honne Gowda A
    Replies:
    2
    Views:
    873
    Karl Heinz Buchegger
    Oct 31, 2003
  2. andy6
    Replies:
    2
    Views:
    757
    andy6 via DotNetMonster.com
    Jun 9, 2006
  3. Replies:
    2
    Views:
    921
    Bengt Richter
    Aug 1, 2005
  4. Richard Tobin
    Replies:
    24
    Views:
    788
  5. Bob
    Replies:
    5
    Views:
    260
Loading...

Share This Page