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> 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
"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>
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
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
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
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
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>
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?
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
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.
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
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
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
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
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!
"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;}
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
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.
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
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.
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
"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.
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
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
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().
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
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).
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
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.
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
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.
>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.
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 :-) This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
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 <=...
|
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...
|
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;
|
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,
|
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.
...
|
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...
|
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...
|
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...
|
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...
|
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...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
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...
|
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...
|
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,...
|
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...
|
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...
|
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...
| |