473,396 Members | 1,861 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

printf() with too many args -- legal?

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:Th*************@gmail.com>
Nov 15 '05 #1
33 5806
On Fri, 24 Jun 2005 12:58:04 -0400, Kenneth Brody wrote:
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
Nov 15 '05 #2

"Kenneth Brody" <ke******@spamcop.net> wrote in message
news:42***************@spamcop.net...
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:Th*************@gmail.com>

Nov 15 '05 #3


Kenneth Brody wrote:
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."

--
Er*********@sun.com

Nov 15 '05 #4
Kenneth Brody wrote:
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

Nov 15 '05 #5
Mark wrote:
"Kenneth Brody" <ke******@spamcop.net> wrote in message
news:42***************@spamcop.net...
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!


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

Nov 15 '05 #6
Kenneth Brody wrote:

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.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #7
Eric Sosman wrote:

Kenneth Brody wrote:
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."


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:Th*************@gmail.com>

Nov 15 '05 #8
In article <d9**********@news1brm.Central.Sun.COM>,
Eric Sosman <er*********@sun.com> wrote:


Kenneth Brody wrote:
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."


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?

Nov 15 '05 #9
In article <d9**********@yin.interaccess.com>,
Kenny McCormack <ga*****@interaccess.com> wrote:
In article <d9**********@news1brm.Central.Sun.COM>,
Eric Sosman <er*********@sun.com> wrote:


Kenneth Brody wrote:
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."


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.

--
Rouben Rostamian
Nov 15 '05 #10
In article <d9**********@pc18.math.umbc.edu>,
Rouben Rostamian <ro****@pc18.math.umbc.edu> wrote:
In article <d9**********@yin.interaccess.com>,
Kenny McCormack <ga*****@interaccess.com> wrote:
In article <d9**********@news1brm.Central.Sun.COM>,
Eric Sosman <er*********@sun.com> wrote:


Kenneth Brody wrote:
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."
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;
}


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.
Nov 15 '05 #11
Kenny McCormack wrote:
In article <d9**********@news1brm.Central.Sun.COM>,
Eric Sosman <er*********@sun.com> wrote:

Kenneth Brody wrote:
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."


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

Nov 15 '05 #12
Robert Gamble wrote:
Kenny McCormack wrote:
Eric Sosman <er*********@sun.com> wrote:
Kenneth Brody wrote:
> 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."


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.


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."

--
Peter

Nov 15 '05 #13
Peter Nilsson wrote:
Robert Gamble wrote:
Kenny McCormack wrote:
Eric Sosman <er*********@sun.com> wrote:
>Kenneth Brody wrote:
>> 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."

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.


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

Nov 15 '05 #14
Robert Gamble wrote:
Kenneth Brody wrote:
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).


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!

Posted Via Usenet.com Premium Usenet Newsgroup Services
----------------------------------------------------------
** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
----------------------------------------------------------
http://www.usenet.com
Nov 15 '05 #15
Robert Gamble wrote:
Kenneth Brody wrote:
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).


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!

Nov 15 '05 #16
"Stan R." <st*********@bremove.lz.hmrprint.com> writes:
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.
--
int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv wxyz.\
\n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
);while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p[i]\
);}return 0;}
Nov 15 '05 #17
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
Nov 15 '05 #18
Kenneth Brody wrote:
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.

--
Simon.
Nov 15 '05 #19
In article <42**********@spool9-west.superfeed.net>,
Stan R. <st*********@bremove.lz.hmrprint.com> wrote:
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

Nov 15 '05 #20
Simon Biber <ne**@ralmin.cc> writes:
Kenneth Brody wrote:
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.


The *printf() functions are somewhat special in that they're part of
the standard library, so the compiler is allowed to make assumptions
about what they do. For example, a call like

printf("%d", 1.5);

invokes undefined behavior. The compiler is allowed to issue a
diagnostic (which is really beside the point, since a compiler may
issue a diagnostic for any reason at any time), but it's also allowed
to generate code that, for example, aborts the program rather than
calling printf(). And for a correct printf() call like:

printf("%s\n", "Hello, world");

the compiler may replace the printf() call with

puts("Hello, world");

It wouldn't be allowed to do these things for a user-defined
my_printf() function with the same prototype, *unless* it's able to
determine at compilation time (or at link time) how the user-defined
function actually behaves. For functions in the standard library, the
compiler is allowed to make these assumptions without analyzing the
implementation of the function, because the behavior is guaranteed by
the standard.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 15 '05 #21
Richard Tobin wrote:
In article <42**********@spool9-west.superfeed.net>,
Stan R. <st*********@bremove.lz.hmrprint.com> wrote:
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.


Good point, but the arg lists in a case like you described doesn't need
to be so long.

a) Encapsolate the name-value pair to a struct or class, and pass
instances of the struct instead (cutting the arg list in half. Or...

b) Cut it down to one arg by using something of the sort of a linked
list, thus just passing the first pointing, and the function keeps going
until it hits the NULL (end.)

c) not having used c for some time (been using c++ for year now after
using c for a while), I honestly can't remebmer if there are classes,
but iff you, one could write a Map or Hash type class, or just use
<map.h> :-)

Posted Via Usenet.com Premium Usenet Newsgroup Services
----------------------------------------------------------
** SPEED ** RETENTION ** COMPLETION ** ANONYMITY **
----------------------------------------------------------
http://www.usenet.com
Nov 15 '05 #22
"Stan R." <st*********@bremove.lz.hmrprint.com> writes:
Richard Tobin wrote:
In article <42**********@spool9-west.superfeed.net>,
Stan R. <st*********@bremove.lz.hmrprint.com> wrote:
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.


Good point, but the arg lists in a case like you described doesn't need
to be so long.

a) Encapsolate the name-value pair to a struct or class, and pass
instances of the struct instead (cutting the arg list in half. Or...


C has no classes.

Even with C99's compound literals, the call is going to be
considerably more verbose than with alternating name-value arguments.
For example, in C99

func(WIDTH, 40, HEIGHT, 50, LAST_ARG);

might become

func((arg_type){WIDTH, 40},
(arg_type){HEIGHT, 50},
(arg_type){LAST_ARG, 0});

And that's ignoring the possibility of different types of arguments,
which would probably require unions and named designators. It gets
very ugly very quickly.

C90 has no compound literals, so you'd need separate code to
initialize the argument objects before passing them to the function.
b) Cut it down to one arg by using something of the sort of a linked
list, thus just passing the first pointing, and the function keeps going
until it hits the NULL (end.)
Again, you's have to construct the linked list separatey before
calling the function, and destroy it afterwards.
c) not having used c for some time (been using c++ for year now after
using c for a while), I honestly can't remebmer if there are classes,
but iff you, one could write a Map or Hash type class, or just use
<map.h> :-)


See above.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <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.
Nov 15 '05 #23
In article <42**********@spool9-east.superfeed.net>,
Stan R. <st*********@bremove.lz.hmrprint.com> wrote:
a) Encapsolate the name-value pair to a struct or class, and pass
instances of the struct instead (cutting the arg list in half. Or...

b) Cut it down to one arg by using something of the sort of a linked
list, thus just passing the first pointing, and the function keeps going
until it hits the NULL (end.)


In one of the systems of this kind that I used, the original interface
was an array of name-value structs. This was verbose and tedious to
type, and the varargs version was added to make it more usable.

-- Richard
Nov 15 '05 #24
Kenny McCormack wrote:
int foo(int a) { return a; }

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

Works fine on 99.99% of all hardware


Although you'd first have to write a compiler which accepts this.
Christian
Nov 15 '05 #25
In article <42***********************@news.sunsite.dk>,
Christian Kandeler <ch****************@hob.de_invalid> wrote:
Kenny McCormack wrote:
int foo(int a) { return a; }

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

Works fine on 99.99% of all hardware


Although you'd first have to write a compiler which accepts this.

Christian


I'm sure compilers exist (from the early dawn era of prototypes)
that would, but today, you would just rearrange it to:

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

And ignore the warning about implicit declaration of foo().

Nov 15 '05 #26
Kenny McCormack wrote:

In article <42***********************@news.sunsite.dk>,
Christian Kandeler <ch****************@hob.de_invalid> wrote:
Kenny McCormack wrote:
int foo(int a) { return a; }

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

Works fine on 99.99% of all hardware

Works fine? Meaning that you don't know what it does
and you don't know what it's supposed to do?

What is bar supposed to do?
A function call to bar has no value and no side effects.

It's just simply undefined.

N869
6.5.2.2 Function calls
Constraints
[#2] If the expression that denotes the called function has
a type that includes a prototype, the number of arguments
shall agree with the number of parameters.

6.8.6.4 The return statement
Constraints
[#1] A return statement with an expression shall not appear
in a function whose return type is void.
Although you'd first have to write a compiler which accepts this.


--
pete
Nov 15 '05 #27
In article <42***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
Kenny McCormack wrote:

In article <42***********************@news.sunsite.dk>,
Christian Kandeler <ch****************@hob.de_invalid> wrote:
>Kenny McCormack wrote:
>
>> int foo(int a) { return a; }
>>
>> void bar(void) { return foo(1,2,3); }
>>
>> Works fine on 99.99% of all hardware


Works fine? Meaning that you don't know what it does
and you don't know what it's supposed to do?


OK, little boy. Change it to "int bar" if it makes you happy.

Or change it from "return foo" to "printf foo" (with suitable syntax to
make it compilable).

Nov 15 '05 #28
Kenny McCormack wrote:

In article <42***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
Kenny McCormack wrote:

In article <42***********************@news.sunsite.dk>,
Christian Kandeler <ch****************@hob.de_invalid> wrote:
>Kenny McCormack wrote:
>
>> int foo(int a) { return a; }
>>
>> void bar(void) { return foo(1,2,3); }
>>
>> Works fine on 99.99% of all hardware


Works fine? Meaning that you don't know what it does
and you don't know what it's supposed to do?


OK, little boy. Change it to "int bar" if it makes you happy.

Or change it from "return foo" to "printf foo"
(with suitable syntax to make it compilable).


The point,
is that you're not paying attention to what you're saying,
because you know better than to do that.

--
pete
Nov 15 '05 #29
In article <42***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
Kenny McCormack wrote:

In article <42***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
>Kenny McCormack wrote:
>>
>> In article <42***********************@news.sunsite.dk>,
>> Christian Kandeler <ch****************@hob.de_invalid> wrote:
>> >Kenny McCormack wrote:
>> >
>> >> int foo(int a) { return a; }
>> >>
>> >> void bar(void) { return foo(1,2,3); }
>> >>
>> >> Works fine on 99.99% of all hardware
>
>Works fine? Meaning that you don't know what it does
>and you don't know what it's supposed to do?


OK, little boy. Change it to "int bar" if it makes you happy.

Or change it from "return foo" to "printf foo"
(with suitable syntax to make it compilable).


The point,
is that you're not paying attention to what you're saying,
because you know better than to do that.


I see what you mean, but I think there is a sense in which you ought to be
able to read text posted here for content and in context - rather than just
looking for any little thing to nit-pick.

Obviously, the point of the thread and the thing being discussed was the
calling of foo() with more parameters than it was declared with. I think it
was clear enough to anyone what the point was, unless, of course, the
reader is, as is all too common in this ng, just reading to look for
something to nitpick. The declaration and use of bar was clearly outside
of the main channel of the discussion.

Nov 15 '05 #30
Kenny McCormack wrote:
>> Kenny McCormack wrote:
>>
>>> int foo(int a) { return a; }
>>>
>>> void bar(void) { return foo(1,2,3); }
>>>
.... snip ...
Obviously, the point of the thread and the thing being discussed
was the calling of foo() with more parameters than it was declared
with. I think it was clear enough to anyone what the point was,
unless, of course, the reader is, as is all too common in this ng,
just reading to look for something to nitpick. The declaration
and use of bar was clearly outside of the main channel of the
discussion.


I believe the excess parameters to foo lead to non-defined
behavior, inasmuch as foo is not a variadic function. I use non-
to include un- and implementation-. I can easily think of a
calling convention in which that call would blow up.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Nov 15 '05 #31
In article <42***************@yahoo.com>,
CBFalconer <cb********@worldnet.att.net> wrote:
....
I believe the excess parameters to foo lead to non-defined
behavior, inasmuch as foo is not a variadic function. I use non-
to include un- and implementation-. I can easily think of a
calling convention in which that call would blow up.


Of course. That's pretty much the reason for existence (or however the
French would say that...) of the "cdecl" calling convention. I would
imagine that the original authors of C invented cdecl (though they may not
have called it that) precisely so that printf() could be implemented.

Notes for the prissy:
1) I say "cdecl", using that as a term in and of itself, to avoid
any implication that the cdecl calling convention is part of or
gets any funding from or is in any way associated with the
C language (the holy grail of this ng).
2) It is probably OT to even mention calling conventions, but
I personally think it is OK to discuss cdecl as long as we make
it clear, as we must, that it is technically OT.

Nov 15 '05 #32
>In article <42***************@yahoo.com>,
CBFalconer <cb********@worldnet.att.net> wrote:
I believe the excess parameters to foo lead to non-defined
behavior, inasmuch as foo is not a variadic function. I use non-
to include un- and implementation-. I can easily think of a
calling convention in which that call would blow up.

(It is indeed undefined behavior, and it does in fact break on
x86 architecture systems that use the "RET N" instruction form
for fixed-argument functions. What happens, of course, is that
the "RET 12" or whatever in the fixed-argument callee removes the
wrong number of bytes from the caller's stack frame, so that
after calling the function, all your local variables go kaboom.
Depending on whether the caller uses ENTER/EXIT and/or a frame
pointer, the caller itself may also not be able to return.)

In article <d9**********@yin.interaccess.com>
Kenny McCormack <ga*****@interaccess.com> wrote:Of course. That's pretty much the reason for existence (or however the
French would say that...) of the "cdecl" calling convention. I would
imagine that the original authors of C invented cdecl (though they may not
have called it that) precisely so that printf() could be implemented.

Notes for the prissy:
1) I say "cdecl", using that as a term in and of itself, to avoid
any implication that the cdecl calling convention is part of or
gets any funding from or is in any way associated with the
C language (the holy grail of this ng).
2) It is probably OT to even mention calling conventions, but
I personally think it is OK to discuss cdecl as long as we make
it clear, as we must, that it is technically OT.


To me, the word "cdecl" refers to the program for turning C
declarations into pseudo-English and vice versa :-) ... as in:

% cdecl
cdecl> explain int (*foo)(arg)
declare foo as pointer to function (arg) returning int
cdecl> declare p as pointer to array 3 of pointer to function (args) returning pointer to pointer to char
char **((*p)[3])(args)

(Note: my copy of cdecl disappeared long ago and the above is made
up from memory.)

That said, there are some fundamental errors above.

C grew out of the B -> NB (New B) -> C progression, as Dennis
Ritchie has noted. The first C compilers were done on the PDP-11.
(See http://cm.bell-labs.com/cm/cs/who/dmr/chist.html for details.)
The PDP-11 has a hardware-denoted "stack pointer" register ("sp")
with "push" and "pop" semantics implied by its subroutine call
instruction. (As with many such machines, there are separate "user"
and "kernel"/"system" stack pointers as well, controlled by the
"PSW" or Processor Status Word. As such, one can talk about the
"usp" vs the "ssp": user and system stack pointers. But this is
invisible to ordinary user programs.)

The "most natural" design of assembly code on the PDP-11 has the
stack pointer adjusted by the caller. The reason is that if you
are going to put arguments on the stack, then call a function, you
end up with a stack on which the return address is at the bottom,
and a "return from subroutine" instruction pops it automatically,
but leaves the arguments on the stack. Unlike the x86, there is
no "return and pop more arguments" instruction -- you must use a
separate pop (or add), and of course, this has to go in the caller,
because the "ret" has returned.

Given these "machine facts", as it were, the obvious, simple, easy
way to handle subroutine calls in a language that supports recursion
and uses the machine's stack is to evaluate the arguments right to
left, pushing each value as soon as it is computed, and then emit
the "call subroutine" instruction followed by the "pop as many bytes
as we pushed" instruction. Variadic routines are easy to write as
well. If you take the address of the stack element just above the
return-address, you have a pointer to the first argument. Each
subsequent argument is the next two bytes (because all arguments
are "int"s -- early C did not have "long" and nobody actually used
floating-point :-) ). You could even write an "nargs" function:
just trace up the call stack, look at the instruction following the
call, and figure out how many bytes it pops (and divide by two since
two PDP-11 bytes gives you one PDP-11 int).

Of course, "nargs" stops working once you support "long" and
floating-point ("double") arguments, which use 4 and 8 bytes (2
and 4 ints) respectively. (It also stops working when you get a
big separate-I&D PDP-11 and are unable to read instructions
because they are in the wrong address space.)

The problems came in when C started growing up and trying to move
out of the restricted "everything is a PDP-11" world. Suddenly
there were Honeywell machines with 9-bit bytes, the Interdata with
32-bit "int"s, machines on which "char" should properly be unsigned,
and so on. And of course, there were machines like the Intel x86,
with its "RET 12" instructions that both returned *and* popped
arguments off the caller's stack -- but required knowing for sure
exactly how many bytes to pop.

The ANSI C89 folks decided to allow Microsoft and other vendors
to use the "RET 12" style instructions, by the simple means of
requiring that a prototype be in scope before calling variadic
functions like printf(). The C compiler could assume that a call
like:

f(1, 2L);

that passed 6 bytes called a non-variadic function f() that ended
with a "RET 6". On the other hand, given:

int g(int, ...);
g(1, 2L);

that same C compiler would know that g() used a plain "RET"
instruction, and pop the 6 bytes itself.

Fortunately, the Intel x86 CPU remained obscure and was never used
in any popular hardware, so nobody actually has to declare their
variadic functions in advance. :-) (OK, I *am* kidding: fortunately,
C compiler vendors used the slower ret-and-separate-pop instruction
sequence, so that C programmers could get away with sloppy code.
And as it turns out, ret-and-separate-pop is now often faster
anyway.)
--
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.
Nov 15 '05 #33
Chris Torek wrote:
[...]
To me, the word "cdecl" refers to the program for turning C
declarations into pseudo-English and vice versa :-) ... as in:

% cdecl
cdecl> explain int (*foo)(arg)
declare foo as pointer to function (arg) returning int
cdecl> declare p as pointer to array 3 of pointer to function
(args) returning pointer to pointer to char char **((*p)[3])(args)

(Note: my copy of cdecl disappeared long ago and the above is made
up from memory.)


Well your memory seems to be exellent:

$ cdecl
Type `help' or `?' for help
cdecl> explain int (*foo)(arg)
declare foo as pointer to function (arg) returning int
cdecl> declare p as pointer to array 3 of pointer to function (args)
returning pointer to pointer to char

char **(*(*p)[3])(args)

Thats copied right out of my linux shell window.

Just thought you might be curious :-)

Nov 15 '05 #34

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Grumble | last post by:
Hello, I have the following structure: struct foo { char *format; /* format string to be used with printf() */ int nparm; /* number of %d specifiers in the format string */ /* 0 <= nparm <=...
7
by: sunfiresg | last post by:
During an interview, I am asked to answer a question: Printf is a major formatted output function provided by the standard C library. Printf accepts a formatting string followed by a various...
31
by: DeltaOne | last post by:
#include<stdio.h> typedef struct test{ int i; int j; }test; main(){ test var; var.i=10; var.j=20;
9
by: geek | last post by:
Hi all, Why does a printf("%d") statement prints this as output and when I do printf("%c") it doesn't print anything. -13361016 Any help would be appreciated. Thanks,
5
by: bg_ie | last post by:
Hi, I'd like to write a function like printf, which takes a string as its first arguement, but then a variable number of arguements after this, based on the contents of the first arguement. ...
18
by: sam_cit | last post by:
Hi Everyone, int main() { printf("not included stdio.h"); } Yes, i haven't included stdio.h and my compiler would generate a warning and would assume that it would return a int, my question...
0
by: =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?= | last post by:
On Nov 10, 6:26 pm, Tomás Ó hÉilidhe <t...@lavabit.comwrote: You use the TOE_PLATFORM macro to choose your platform. 1 is Unix. 2 is Windows. Here's what I've got so far. Any comments are...
9
by: RahulJain83 | last post by:
Hi, I am Rahul. We have a complete software written out (with n other shared libraries maintained by various other teams). The shared libraries are loaded at run time by the main executable...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.