printf() with too many args -- legal?

K

Kenneth Brody

I know that passing printf() too few arguments, or arguments of the wrong
type invokes UB. However, what about passing too many arguments, if the
expected arguments are of the correct type?

For example:

char format1[] = "foo %s bar %s baz %d";
char format2[] = "foo %s bar %s no baz here";

char *strvar1 = "one", *strvar2 = "two";
int intvar = 123;

....

printf( some_condition ? format1 : format2, strvar1, strvar2, intvar );

When "some_condition" is false, printf() will expect two strings, but will
be passed two strings and an int.

Yes, I know this can be rewritten as:

if ( some_condition )
printf(format1,strvar1,strvar2,intvar);
else
printf(format2,strvar1,strvar2);

However, this construct appears in numerous places throughout existing
code, which works on all current platforms it's ported to. I'd like to
make sure that it won't cause problems on some future platform.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
M

Mark

Kenneth Brody said:
I know that passing printf() too few arguments, or arguments of the wrong
type invokes UB. However, what about passing too many arguments, if the
expected arguments are of the correct type?
They can't be the correct type if they're not expected!
But that's actually good news for you... additional arguments will not be
seen as the function only requests arguments as it encounters conversion
specifiers in the format string.

Mark
For example:

char format1[] = "foo %s bar %s baz %d";
char format2[] = "foo %s bar %s no baz here";

char *strvar1 = "one", *strvar2 = "two";
int intvar = 123;

....

printf( some_condition ? format1 : format2, strvar1, strvar2, intvar );

When "some_condition" is false, printf() will expect two strings, but will
be passed two strings and an int.

Yes, I know this can be rewritten as:

if ( some_condition )
printf(format1,strvar1,strvar2,intvar);
else
printf(format2,strvar1,strvar2);

However, this construct appears in numerous places throughout existing
code, which works on all current platforms it's ported to. I'd like to
make sure that it won't cause problems on some future platform.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com |
|
| kenbrody/at\spamcop.net | www.fptech.com | #include
<std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
E

Eric Sosman

Kenneth said:
I know that passing printf() too few arguments, or arguments of the wrong
type invokes UB. However, what about passing too many arguments, if the
expected arguments are of the correct type?

Legal. 7.19.6.1/2: "If the format is exhausted while
arguments remain, the excess arguments are evaluated (as
always) but are otherwise ignored."
 
R

Robert Gamble

Kenneth said:
I know that passing printf() too few arguments, or arguments of the wrong
type invokes UB. However, what about passing too many arguments, if the
expected arguments are of the correct type?

That is fine as long as, of course, the total number of arguments
provided is within the limits of your implementation (which is at least
127 in c99, 31 in c90).

Robert Gamble
 
R

Robert Gamble

They can't be the correct type if they're not expected!

He said if the *expected* arguments are of the correct type, meaning
that the aguments that *are* expected, based on the format string
provided, are all provided and of the correct type.

Robert Gamble
 
L

Lawrence Kirby

I know that passing printf() too few arguments, or arguments of the wrong
type invokes UB. However, what about passing too many arguments, if the
expected arguments are of the correct type?

That's fine, it isn't necessary for a variable argument function to read
the whole variable argumet list.

Lawrence
 
C

CBFalconer

Kenneth said:
I know that passing printf() too few arguments, or arguments of
the wrong type invokes UB. However, what about passing too many
arguments, if the expected arguments are of the correct type?

For example:
char format1[] = "foo %s bar %s baz %d";
char format2[] = "foo %s bar %s no baz here";
char *strvar1 = "one", *strvar2 = "two";
int intvar = 123;
....
printf( some_condition ? format1 : format2, strvar1, strvar2, intvar );

When "some_condition" is false, printf() will expect two strings,
but will be passed two strings and an int.

Yes, I know this can be rewritten as:

if ( some_condition )
printf(format1,strvar1,strvar2,intvar);
else
printf(format2,strvar1,strvar2);

However, this construct appears in numerous places throughout
existing code, which works on all current platforms it's ported to.
I'd like to make sure that it won't cause problems on some future
platform.

It's fine. It probably saves a few bytes of object code. The
principal objection is that that sort of construct usually prevents
the compiler from checking the arguments against the format
specifiers, so it is more error prone on revision.
 
K

Kenneth Brody

Eric said:
Legal. 7.19.6.1/2: "If the format is exhausted while
arguments remain, the excess arguments are evaluated (as
always) but are otherwise ignored."

Thanks. (And thanks to everyone else who answered.) I had a feeling
that that would be the case, but the *printf() functions seem to be
"special", in that the compiler can do type-checking at compile time
(given a literal format specifier), and I was afraid that there might
be some other "special" things about it.

Actually, it's a little more complex than the example I gave, but the
net result is the same.

Glad to see that I don't have to worry about this breaking on some
future platform.

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Kenny McCormack

Legal. 7.19.6.1/2: "If the format is exhausted while
arguments remain, the excess arguments are evaluated (as
always) but are otherwise ignored."

In the religious canon of this group, is printf(), then, special?

Does this license extend to all functions, or to only variadic functions,
or only to the printf() family?
 
R

Rouben Rostamian

In the religious canon of this group, is printf(), then, special?

Does this license extend to all functions, or to only variadic functions,
or only to the printf() family?

What do you exactly mean by "this license"?

Look at this function:

void foo(int a)
{
return;
}

Isn't this a perfectly legal C function? Note that
the argument is not used. There's nothing wrong with
not using an argument.
 
K

Kenny McCormack

What do you exactly mean by "this license"?

Look at this function:

void foo(int a)
{
return;
}

Some compilers will issue a warning for this (unused argument).
Not that that is either here or there...
Isn't this a perfectly legal C function? Note that
the argument is not used. There's nothing wrong with
not using an argument.

But that's not my point. My point is:

int foo(int a) { return a; }

void bar(void) { return foo(1,2,3); }

Works fine on 99.99% of all hardware (that anyone seriously cares about
[*]), but is, as I understand the canon law, not allowed by in the religion
of this NG.

[*] Obvious flame bait.
 
R

Robert Gamble

Kenny said:
In the religious canon of this group, is printf(), then, special?

Does this license extend to all functions, or to only variadic functions,
or only to the printf() family?

This "license" applies to all variadic functions.

In c90, this also applies to functions that do not have a prototype in
scope, in c99 this is undefined behavior.

Robert Gamble
 
P

Peter Nilsson

Robert said:
This "license" applies to all variadic functions.

In c90, this also applies to functions that do not have a prototype in
scope, in c99 this is undefined behavior.

Passing he wrong number (and/or promoted type) of arguments to a non
prototyped function invokes undefined behaviour in both C90 and C99.

ANSI 3.3.2.2: "If the expression that denotes the called function has a
type that does not include a prototype, the integral 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 agree with the number of
parameters,
the behavior is undefined."
 
R

Robert Gamble

Peter said:
Passing he wrong number (and/or promoted type) of arguments to a non
prototyped function invokes undefined behaviour in both C90 and C99.

ANSI 3.3.2.2: "If the expression that denotes the called function has a
type that does not include a prototype, the integral 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 agree with the number of
parameters,
the behavior is undefined."

Whoops, I was confusing "not a contraint violation" with "not undefined
behavior". It turns out that this is not a constraint violation in
either version but it is, as you pointed out, UB in both.

Robert Gamble
 
S

Stan R.

Robert said:
That is fine as long as, of course, the total number of arguments
provided is within the limits of your implementation (which is at
least 127 in c99, 31 in c90).

Going out on a limb here, but has anyone ever written (for practical
use) a function that /actually/ /took/ 127 args?!?!?! (I almost cringe
at the though of a function declaration taking up half a page! :p )

Even 31 seems big for an arg list!
 
S

Stan R.

Robert said:
That is fine as long as, of course, the total number of arguments
provided is within the limits of your implementation (which is at
least 127 in c99, 31 in c90).

Going out on a limb here, but has anyone ever written (for practical
use) a function that /actually/ /took/ 127 args?!?!?! (I almost cringe
at the though of a function declaration taking up half a page! :p )

Even 31 seems big for an arg list!
 
B

Ben Pfaff

Stan R. said:
Going out on a limb here, but has anyone ever written (for practical
use) a function that /actually/ /took/ 127 args?!?!?! (I almost cringe
at the though of a function declaration taking up half a page! :p )

Such a long argument list is far more likely to occur in
machine-generated code than in code written by a human.
 
L

Lawrence Kirby

On Fri, 24 Jun 2005 23:58:51 +0000, Kenny McCormack wrote:

....
But that's not my point. My point is:

int foo(int a) { return a; }

void bar(void) { return foo(1,2,3); }

Works fine on 99.99% of all hardware (that anyone seriously cares about
[*]), but is, as I understand the canon law, not allowed by in the religion
of this NG.

[*] Obvious flame bait.

This isn't flame-bait it is simply wrong. It is not hardware that
determines this, it is the calling conventions used by the compiler.

In pre-standard C where there wasn't explicit syntax for variable argument
functions the language allowed any function to be variable argument, or
at least it didn't forbit it. So when the called function was compiled the
compiler didn't in general know how what arguments the caller actually
passed therefore didn't know how much to clean up on return. Such
compilers tended to use what is loosely referred to a "C calling
conventions" where the caller cleans up after the return. Under this
system the code above will "work".

In standard C the arguments passed in a function call must match the
parameters specified in the definition. A variable argument list has to be
stated explicitly using the ... notation and it is invalid to call a
variable argument function without the ... prototype in scope. So a
standard C compiler has the option to use "called function cleans up on
return" conventions (sometimes referred to as "Pascal calling
conventions") on everything other than explcitly declared variable
argument lists.

So standard C compilers can use Pascal calling conventions which would
break the code above. However C calling conventions are well established
on many platforms so many compilers still use them for link compatibility.
However even then a good compilers can use Pascal calling conventions
when they can, e.g. for static non variable argument functions. Some
compilers allow you to control this behaviour.

Lawrence
 
S

Simon Biber

Kenneth said:
Thanks. (And thanks to everyone else who answered.) I had a feeling
that that would be the case, but the *printf() functions seem to be
"special", in that the compiler can do type-checking at compile time
(given a literal format specifier), and I was afraid that there might
be some other "special" things about it.

They aren't special, from a language point of view. A standard C
compiler is not required to do type-checking of the variable arguments
of printf functions. The fact that some compilers do this is an extra,
non-standardised feature.
 
R

Richard Tobin

Stan R. said:
Going out on a limb here, but has anyone ever written (for practical
use) a function that /actually/ /took/ 127 args?!?!?! (I almost cringe
at the though of a function declaration taking up half a page! :p )

Even 31 seems big for an arg list!

Some graphical interfaces have used vararg/stdarg argument lists with
alternating name-value arguments, and these can quite reasonably be
fairly long, though more than 30 arguments would be unusual even for
this case.

-- Richard
 

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

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top