Variadic Functions and default argument promotions

A

amit.codename13

Are default argument promotions applied to the arguments of a variadic
function whose prototype is included(ending with ellipses) ?
 
J

jacob navia

Are default argument promotions applied to the arguments of a variadic
function whose prototype is included(ending with ellipses) ?

To the arguments that are part of the variable part yes.
 
A

amit.codename13

To the arguments that are part of the variable part yes.

6.5.2.2

i am trying to interpret the above text. Doesn't it say that having a
prototype ending with an ellipsis leads to an undefined behavior...
if its an undefined behavior how can it be certain if default argument
promotions are applied or not...
are there other clauses that deal with this issue?
 
A

amit.codename13

To the arguments that are part of the variable part yes.

the text above says that if a function prototype with ellipsis is
included the behavior is undefined so how can it be certain if default
argument promotions are applied to them or not...

are there other clauses that deal with this issue?
 
E

Eric Sosman

the text above says that if a function prototype with ellipsis is
included the behavior is undefined so how can it be certain if default
argument promotions are applied to them or not...

are there other clauses that deal with this issue?

Widen your view to include the rest of the quoted paragraph,
whose topic is what happens when a function is called in the
absence of prototype information. If there's no prototype in
sight at the point of the call and the actual definition of the
called function has a variadic argument list, the behavior is
undefined. For example,

int main(void) {
int printf(); /* declaration sans prototype */
printf ("Hello, world!\n");
return 0;
}

produces undefined behavior, because the printf() declaration
in force at the point of call has no prototype information, while
the actual printf() function in the library is defined with a
prototype ending in ,...) .

Some functions can be called without a prototype in sight;
this is an accommodation for pre-Standard code from the days
when C had no function prototypes. New code should almost never
use this capability -- and *cannot* use it for variadic functions,
or for functions whose parameters are of promotable types. That
is, there is no way to call

void func(float f) { ... }

without a prototype, because the default argument promotions
cannot pass an un-promoted `float'.
 
A

amit.codename13

     Widen your view to include the rest of the quoted paragraph,
whose topic is what happens when a function is called in the
absence of prototype information.  If there's no prototype in
sight at the point of the call and the actual definition of the
called function has a variadic argument list, the behavior is
undefined.  For example,

        int main(void) {
            int printf();  /* declaration sans prototype */
            printf ("Hello, world!\n");
            return 0;
        }

produces undefined behavior, because the printf() declaration
in force at the point of call has no prototype information, while
the actual printf() function in the library is defined with a
prototype ending in ,...) .

     Some functions can be called without a prototype in sight;
this is an accommodation for pre-Standard code from the days
when C had no function prototypes.  New code should almost never
use this capability -- and *cannot* use it for variadic functions,
or for functions whose parameters are of promotable types.  That
is, there is no way to call

        void func(float f) { ... }

without a prototype, because the default argument promotions
cannot pass an un-promoted `float'.

got it...

i have one more query...

so, does that clause say about the arguments after promotion or before
promotion?
 
E

Eric Sosman

got it...

i have one more query...


so, does that clause say about the arguments after promotion or before
promotion?

After promotion, because printf() never sees the arguments
but only the parameters that were initialized from them. (All
C functions work this way: Argument expressions initialize the
function parameters, and the function works with the parameters.
That's why you can use something like `getchar()' as an argument
without fear that the called function will read a new character
every time it refers to the corresponding parameter.)

Some conversion specifiers can include a length modifier;
for example, "%hd" converts an int that was promoted from a
short. I must admit I've never understood why these were of
any use, but maybe there's a subtle case I've never bothered
to dig into. Perhaps they're there for symmetry with scanf(),
where "%hd" *is* different from "%d" in an important way.
There's also the "%n" printf() specifier; again, "%hn" differs
from plain "%n". But for the ordinary output-generating
conversion specifiers, "%hd" and "%hhd" ring no bells with me.
 
K

Keith Thompson

the text above says that if a function prototype with ellipsis is
included the behavior is undefined so how can it be certain if default
argument promotions are applied to them or not...

are there other clauses that deal with this issue?

See my previous response.

It actually took me a couple of readings to make sense of that
paragraph in the standard (C99 6.5.2.2p6). The trick is to keep in
mind the distinction between declaration and definition.

If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed
on each argument, and arguments that have type float are promoted
to double. These are called the default argument promotions. If
the number of arguments does not equal the number of parameters,
the behavior is undefined. If the function is defined with a type
that includes a prototype, and either the prototype ends with an
ellipsis (, ...) or the types of the arguments after promotion are
not compatible with the types of the parameters, the behavior is
undefined. 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:

The type of "the expression that denotes the called function" depends
on the declaration visible at the point of the call. The phrase "If
the function is defined with a type that includes a prototype" refers
to the *definition* of the function; the definition included a
declaration, but that declaration isn't necessarily visible at the
point of the call.

What might not be 100% clear is that this sentence:

If the function is defined with a type that includes a prototype,
and either the prototype ends with an ellipsis (, ...) or the
types of the arguments after promotion are not compatible with the
types of the parameters, the behavior is undefined.

applies *only* if the visible declaration does not include a
prototype.

In other words, if the function is defined with a prototype, but that
prototype isn't visible to the caller, the caller must provide
compatible arguments (they won't be converted). Similarly, if the
function is defined with a prototype that includes ", ...", and that
prototype isn't visible to the caller, then the behavior is undefined
regardless of what arguments are passed; the caller has to know that
the called function is variadic, or it can't safely call it at all.

Cases where the visible declaration does include a prototype are
covered in later paragraphs.
 
E

Eric Sosman

christian.bau said:
I don't think it is very useful, but it will print the value of
(short) x when you pass x as the parameter.

So if you pass short s it gets promoted to int, printf converts it
back to short (unchanged) and prints it.
If you pass int i, it gets passed to printf unmodified, but printf
converts it to short before printing it.

Hmmm. I guess that would make a difference only if the
original int argument had a value that was out of range for
short -- Which means that if printf() is written in C, we're
into the "implementation-defined result or implementation-
defined signal" thicket ...
 
A

amit.codename13

I don't think it is very useful, but it will print the value of
(short) x when you pass x as the parameter.

So if you pass short s it gets promoted to int, printf converts it
back to short (unchanged) and prints it.
If you pass int i, it gets passed to printf unmodified, but printf
converts it to short before printing it.

if printf converts promoted arguments to the types as specified by the
conversion specifiers,
the conversions are done as per the Converson section 6.3
when will 7.19.6.1.p9 come into use?
 
J

James Kuyper

if printf converts promoted arguments to the types as specified by the
conversion specifiers,

This conversion only occurs when the promoted type corresponding to the
type indicated by the conversion specifier is different from type
indicated by the specifier.
the conversions are done as per the Converson section 6.3
when will 7.19.6.1.p9 come into use?

There are four types that are relevant here. Let type_a be the type of
the argument to fprintf(), and let type_ap be the corresponding promoted
type. Let type_s be the type indicated by the conversion specifier, and
let type_sp be the corresponding promoted type.

fprintf() attempts to extract a parameter value of type type_sp from
it's argument list (by a mechanism similar to va_arg(), though it need
not actually use va_arg()). The value is then converted to type_s, if
necessary (it can only be necessary if type_sp is different from type_s).

7.19.6.1p9 applies whenever type_ap is different from type_sp. The
problem is NOT the conversion to type_s, it's the extraction from the
argument list of a value of type type_sp, If type_ap is incompatible
with type_sp, that extraction has undefined behavior (7.15.11p2).

However, 7.19.6.1p9 is worded a little more strongly than that. It
doesn't just require that type_sp be compatible with type_ap; it says
that the behavior is undefined unless type_s is the same as type_a. This
is not something that can be easily explained in terms of the fprintf()
being written as an ordinary C function using the <stdarg.h> mechanisms
to extract it's arguments, since those mechanisms are not sensitive in
any way to the argument's type before promotion. Possibly, this is a
defect in the standard.

However, it's possible to imagine an implementation of fprintf() that
could be sensitive to cases where type_a was not the same as type_s,
even though type_ap is compatible with type_sp. We have to assume, first
of all, that the argument passing mechanism contains or at least depends
upon the type_a, and not just upon type_ap. The <stdarg.h> mechanisms
provide no mechanisms that depend upon the original type, rather than
the promoted type. However, as a non-standard extension, a fully
conforming implementation of C could add features to <stdarg.h> that do
depend upon the type before promotion. Those features could not
interfere with any user code that restricts itself to using the
standard-defined features. However, fprintf() could use these
extensions, and thereby become sensitive to any difference between
type_a and type_s.
I can't think of any good reason for doing this, other than sheer
perversity, but as currently worded, 7.19.6.1p9 allows such an
implementation.
 
B

Barry Schwarz

if printf converts promoted arguments to the types as specified by the
conversion specifiers,
the conversions are done as per the Converson section 6.3
when will 7.19.6.1.p9 come into use?

printf doesn't perform the conversion. That occurs while the calling
function is building the "argument list". It occurs completely
independent of the conversion specifiers. If you specify %s but the
argument is a char, the char is promoted to int per 6.3.1.8. 7.19.6.1
tells you that when printf tries to process it undefined behavior
occurs.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top