469,117 Members | 1,338 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,117 developers. It's quick & easy.

P 155 k&r section 7.3

mdh
Hi All,
The section is titled Variable-length Argument lists.
May I ask a question about the use of "macros".
To quote K&R.

"The standard header <stdarg.hcontains a set of macro definitions
that define how to step through an argument list...... The type
va_list is used to declare a variable...in minprintf..ap
.......The macro va_start initializes ap to point to the first unnamed
argument."

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.

thanks in advance.

Sep 5 '08 #1
45 1694
mdh <md**@comcast.netwrites:
The section is titled Variable-length Argument lists.
May I ask a question about the use of "macros".
To quote K&R.

"The standard header <stdarg.hcontains a set of macro definitions
that define how to step through an argument list...... The type
va_list is used to declare a variable...in minprintf..ap
......The macro va_start initializes ap to point to the first unnamed
argument."

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.
The reason va_start, va_arg, va_end, and va_copy are defined as macros
is that they *can't* be defined as functions.

For example, va_arg takes two arguments, an expression of type va_list
(I'm actually not sure it can be an arbitrary expression) and a type
name. It yields a result of the named type. A C function cannot take
a type name as an argument, only an expression, and it must return a
result of some single type that's specified when the function is
declared.

Now va_arg can't *portably* be defined as a macro either -- but
there's always some way to define it non-portably. In some cases, it
might even be necessary for the compiler to provide some extension
just for the purpose, and have the va_arg macro use that extension;
for example, an implementation might have something like

#define va_arg(ap, type) __builtin_va_arg__(ap, type)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 6 '08 #2
mdh wrote:
Hi All,
The section is titled Variable-length Argument lists.
May I ask a question about the use of "macros".
To quote K&R.

"The standard header <stdarg.hcontains a set of macro definitions
that define how to step through an argument list...... The type
va_list is used to declare a variable...in minprintf..ap
......The macro va_start initializes ap to point to the first unnamed
argument."

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.
You can't do this:

va_arg(arg, int)

with a function.

--
pete
Sep 6 '08 #3
mdh
On Sep 5, 5:20*pm, Keith Thompson <ks...@mib.orgwrote:
mdh <m...@comcast.netwrites:
The section is titled Variable-length Argument lists.
May I ask a question about the use of "macros".
To quote K&R.
"The standard header <stdarg.hcontains a set of macro definitions

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.

The reason va_start, va_arg, va_end, and va_copy are defined as macros
is that they *can't* be defined as functions.

For example, va_arg takes two arguments, an expression of type va_list
(I'm actually not sure it can be an arbitrary expression) and a type
name. *It yields a result of the named type. *A C function cannot take
a type name as an argument, only an expression,


So, in the example that is given on p156,

void minprintf(char *fmt, ...){

va_list ap;

? This declares ap a pointer of type va_list? And the reason ap is a
pointer is simply because that is the way it is defined??
Then,

va_start(ap, fmt);

So, from what you say, if I understand this, the type here (fmt) is
"pointer to char" and the expression 'ap' is initialized or "returned"
as a pointer to char (to the first argument)?

And just to make sure, an example here of va_arg use.
ival is declared an int.

so the expression

ival=va_arg(ap, int) will return a value ( ival) that is of
whatever_type ....in this case int, but could be char *, char etc?
So, although each of these macros does something a little different,
the common thread seems to be that the type of the argument is
unknown, and these macros provide a mechanism to deal with it?

Sep 6 '08 #4
mdh <md**@comcast.netwrites:
On Sep 5, 5:20*pm, Keith Thompson <ks...@mib.orgwrote:
>mdh <m...@comcast.netwrites:
The section is titled Variable-length Argument lists.
May I ask a question about the use of "macros".
To quote K&R.
"The standard header <stdarg.hcontains a set of macro definitions

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.

The reason va_start, va_arg, va_end, and va_copy are defined as macros
is that they *can't* be defined as functions.

For example, va_arg takes two arguments, an expression of type va_list
(I'm actually not sure it can be an arbitrary expression) and a type
name. *It yields a result of the named type. *A C function cannot take
a type name as an argument, only an expression,


So, in the example that is given on p156,

void minprintf(char *fmt, ...){

va_list ap;

? This declares ap a pointer of type va_list? And the reason ap is a
pointer is simply because that is the way it is defined??
What makes you think va_list is a pointer type? The standard merely
says that it's "an object type suitable for holding information needed
by the macros va_start, va_arg, va_end, and va_copy". It could be a
pointer type, but it could just as easily be a structure or an array.
>
Then,

va_start(ap, fmt);

So, from what you say, if I understand this, the type here (fmt) is
"pointer to char" and the expression 'ap' is initialized or "returned"
as a pointer to char (to the first argument)?
va_start doesn't return anything. It initializes ap, an object of
type va_list. (That's part of the reason it's a macro; a function
can't modify an argument.) The va_list object exists to allow access
to the variadic arguments; you can think of it as a kind of abstract
index into the argument list.

The second argument to va_start is the name of the parameter just
before the ", ...".

The way in which this provides access to the following parameters is
entirely implementation-specific. If arguments are passed on a stack,
for example, a va_list object might be a pointer that gets advanced
through the region of memory containing the parameter objects. Or it
might be pure compiler magic.
And just to make sure, an example here of va_arg use.
ival is declared an int.

so the expression

ival=va_arg(ap, int) will return a value ( ival) that is of
whatever_type ....in this case int, but could be char *, char etc?
Right. Before calling va_arg, you have to already *know* what the
type of the next argument is going to be, and you have to know when to
stop. For something like printf, this is specified by the format
string. Or all the variadic arguments might be of the same pointer
type, with a null pointer marking the end of the list. Other schemes
are possible.

If you get the type wrong, for example if you call va_arg(ap, int)
when the next argument is actually of type char*, then you've just
entered the realm of undefined behavior.
So, although each of these macros does something a little different,
the common thread seems to be that the type of the argument is
unknown, and these macros provide a mechanism to deal with it?
Right.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 6 '08 #5
mdh
On Sep 5, 7:21*pm, Keith Thompson <ks...@mib.orgwrote:
mdh <m...@comcast.netwrites:

va_list ap;
? This declares ap a pointer of type va_list?

What makes you think va_list is a pointer type?
I was **deceived**!!!!

In K&R, va_list ap;

is followed by a comment

/*points to each unnamed arg in turn*/

so I assumed ap must be a pointer. :-)
*The standard merely
says that it's "an object type suitable for holding information needed
by the macros va_start, va_arg, va_end, and va_copy". *It could be a
pointer type, but it could just as easily be a structure or an array.
Then,
va_start(ap, fmt);
So, from what you say, if I understand this, the type here (fmt) is
"pointer to char" and the expression 'ap' is initialized or "returned"
as a pointer to char (to the first argument)?

va_start doesn't return anything. *It initializes ap, an object of
type va_list. *(That's part of the reason it's a macro; a function
can't modify an argument.)

The second argument to va_start is the name of the parameter just
before the ", ...".

The way in which this provides access to the following parameters is
entirely implementation-specific. *If arguments are passed on a stack,
for example, a va_list object might be a pointer that gets advanced
through the region of memory containing the parameter objects. *Or it
might be pure compiler magic.

thank you Keith.

Sep 6 '08 #6
mdh
On Sep 5, 5:20 pm, Keith Thompson <ks...@mib.orgwrote:
mdh <m...@comcast.netwrites:
The section is titled Variable-length Argument lists.

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.

The reason va_start, va_arg, va_end, and va_copy are defined as macros
is that they *can't* be defined as functions.

May I pursue another issue a little further.

K&R (p 155) declare minprintf thus:

void minprintf(char *fmt, ...);
When I followed the example, it did not seem to matter to the output
whether the declaration was

void minprintf(char *fmt, ...);
or

void minprintf(int fmt, ...);
The only difference is ( maybe the **only** will raise some chuckles)
that char *fmt points to all the arguments in my debugger, but int
returns an integer( surprise, surprise!). For fear of flogging a dead
horse, is that the difference?

Sep 6 '08 #7
In article <3d**********************************@b38g2000prf. googlegroups.com>,
mdh <md**@comcast.netwrote:
>On Sep 5, 5:20 pm, Keith Thompson <ks...@mib.orgwrote:
>mdh <m...@comcast.netwrites:
The section is titled Variable-length Argument lists.

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.

The reason va_start, va_arg, va_end, and va_copy are defined as macros
is that they *can't* be defined as functions.


May I pursue another issue a little further.

K&R (p 155) declare minprintf thus:

void minprintf(char *fmt, ...);
When I followed the example, it did not seem to matter to the output
whether the declaration was

void minprintf(char *fmt, ...);
or

void minprintf(int fmt, ...);
On many machines 'int' and 'char *' are the same size, have the same bit
representation, and are, basically, interchangeable. You can't rely on
this being true on all machines, of course...

Sep 6 '08 #8
On Sat, 6 Sep 2008 11:46:27 -0700 (PDT), mdh <md**@comcast.netwrote:
>On Sep 5, 5:20 pm, Keith Thompson <ks...@mib.orgwrote:
>mdh <m...@comcast.netwrites:
The section is titled Variable-length Argument lists.

Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.

The reason va_start, va_arg, va_end, and va_copy are defined as macros
is that they *can't* be defined as functions.


May I pursue another issue a little further.

K&R (p 155) declare minprintf thus:

void minprintf(char *fmt, ...);
When I followed the example, it did not seem to matter to the output
whether the declaration was

void minprintf(char *fmt, ...);
or

void minprintf(int fmt, ...);
How were you able to check the first argument for '%' followed by 'd',
'f', or 's' if its type was int instead of char*?
>

The only difference is ( maybe the **only** will raise some chuckles)
that char *fmt points to all the arguments in my debugger, but int
What does this mean? How can a pointer in your code point to
something in your debugger? For that matter, how do you even pass
arguments to a debugger?
>returns an integer( surprise, surprise!). For fear of flogging a dead
Arguments don't "return" anything. Did you mean your debugger
displayed an integer?
>horse, is that the difference?
What difference? Show your code for a minprintf with an int as its
first parameter and a sample calling statement.

As coded in K&R, minprintf will handle variadic arguments (the ones
implied by the ...) of type int, double, and char* based on the
conversion specification in the format string.

If you change the parameter and argument to an int, how will minprintf
know the type of the next argument to extract? How will it know how
many arguments to extract?

--
Remove del for email
Sep 6 '08 #9
mdh
On Sep 6, 12:03*pm, gaze...@shell.xmission.com (Kenny McCormack)
wrote:
In article <3d002485-0189-49ff-bc1f-b5199f205...@b38g2000prf.googlegroups..com>,
On many machines 'int' and 'char *' are the same size, have the same bit
representation, and are, basically, interchangeable. *You can't rely on
this being true on all machines, of course...

thanks Kenny..there is clearly something I am not seeing...but
hopefully this will become clearer.
Sep 6 '08 #10
mdh
On Sep 6, 12:09*pm, Barry Schwarz <schwa...@dqel.comwrote:
On Sat, 6 Sep 2008 11:46:27 -0700 (PDT), mdh <m...@comcast.netwrote:
On Sep 5, 5:20 pm, Keith Thompson <ks...@mib.orgwrote:
mdh <m...@comcast.netwrites:
K&R (p 155) declare minprintf thus:
void minprintf(char *fmt, ...);
When I followed the example, it did not seem to matter to the output
whether the declaration was
void minprintf(char *fmt, ...);
or
void minprintf(int fmt, ...);

How were you able to check the first argument for '%' followed by 'd',
'f', or 's' if its type was int instead of char*?

I guess that is what I do not get.

>

The only difference is ( maybe the **only** will raise some chuckles)
that char *fmt points to all the arguments in my debugger, but int

What does this mean?
What I mean ( not put too articulately) is that as I step through the
debugger, fmt is displayed, the value of which is the entire argument
in minprintf if fmt is declared at char *fmt, but an integer if
declared as int.
>
>
Arguments don't "return" anything. *Did you mean your debugger
displayed an integer?

correct.

>
horse, is that the difference?

What difference? *Show your code for a minprintf with an int as its
first parameter and a sample calling statement.

As coded in K&R, minprintf will handle variadic arguments (the ones
implied by the ...) of type int, double, and char* based on the
conversion specification in the format string.

If you change the parameter and argument to an int, how will minprintf
know the type of the next argument to extract? *
Well...that is what I am clearly not getting. I **thought** that the
essence of the ellipse ( ...) was that one does not know what the type
and number of the arguments is?
How will it know how many arguments to extract? *
Are you saying that the role of the declaration "char *fmt" is to
tell the compiler that each argument needs to be extracted as a char?

Sep 6 '08 #11
On Sat, 06 Sep 2008 12:30:27 -0700, mdh wrote:
On Sep 6, 12:09*pm, Barry Schwarz <schwa...@dqel.comwrote:
>On Sat, 6 Sep 2008 11:46:27 -0700 (PDT), mdh <m...@comcast.netwrote:
>K&R (p 155) declare minprintf thus:
>void minprintf(char *fmt, ...);
>When I followed the example, it did not seem to matter to the output
whether the declaration was
>void minprintf(char *fmt, ...);
>or
>void minprintf(int fmt, ...);

How were you able to check the first argument for '%' followed by 'd',
'f', or 's' if its type was int instead of char*?

I guess that is what I do not get.
Then, please post a minimal complete program that includes the declaration
void minprintf(int fmt, ...);, defines that function exactly the way you
have defined it now, and calls it.
Sep 6 '08 #12
mdh said:

<snip>
May I pursue another issue a little further.

K&R (p 155) declare minprintf thus:

void minprintf(char *fmt, ...);
When I followed the example, it did not seem to matter to the output
whether the declaration was

void minprintf(char *fmt, ...);
or

void minprintf(int fmt, ...);
If I just change the declaration to suit yours, my compiler issues a
diagnostic message:

foo.c:7: conflicting types for `minprintf'

and halts the compilation.

If I change the declaration /and/ the definition, I get a different
diagnostic message:

foo.c:36: warning: passing arg 1 of `minprintf' makes integer from pointer
without a cast

Can you convince me that these diagnostic messages have no significance?

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 6 '08 #13
mdh <md**@comcast.netwrites:
On Sep 6, 12:09*pm, Barry Schwarz <schwa...@dqel.comwrote:
[...]
>What difference? *Show your code for a minprintf with an int as its
first parameter and a sample calling statement.

As coded in K&R, minprintf will handle variadic arguments (the ones
implied by the ...) of type int, double, and char* based on the
conversion specification in the format string.

If you change the parameter and argument to an int, how will minprintf
know the type of the next argument to extract? *

Well...that is what I am clearly not getting. I **thought** that the
essence of the ellipse ( ...) was that one does not know what the type
and number of the arguments is?
>How will it know how many arguments to extract? *

Are you saying that the role of the declaration "char *fmt" is to
tell the compiler that each argument needs to be extracted as a char?
No.

Here's a sample definition; I don't know whether it exactly matches
what's in K&R, but it's close enough to make the point.

int minprintf(char *fmt, ...)
{
/* ... */
}

The *only* thing the "char *fmt, ..." part of the declaration tells
the compiler is that the first argument is of type char*, and there
will be zero or more arguments of unspecified type(s) following that.
The compiler has absolutely no way of knowing anything more than that.

Which means that it's entirely up to the programmer to make sure that
the arguments passed by the caller and the parameters used by the
callee are consistent.

In printf-like functions, the fmt argument points to a format string
which specifies (not in C, but in a small specialized "language" of
its own) the types of the remaining arguments. For example, if a call
looks like this:

minprintf("%s = %d\n", "foobar", 42);

then minprintf itself needs to make the following calls to fetch the
parameter values:

va_list ap;
va_start(ap, fmt);
va_arg(ap, char*);
va_arg(ap, int);
va_end(ap);

How does it know to call va_arg with char* and then with int? The
format string tells it; it needs to respond to "%s" by calling
va_arg(ap, char*), and to "%d" by calling va_arg(ap, int).

If the first argument were an int rather than a char*, then minprintf
wouldn't have any way of knowing what argument values to grab.

And if the caller accidentally passes inconsistent arguments:

minprintf("%s = %s\n", "foobar", 42);

or if minprintf itself handes the arguments incorrectly, for example
by calling va_arg(ap, unsigned long) in response to "%d", then the
behavior is undefined; the compiler can't even diagnose the error.

(As a special case, some compilers, such as gcc, understand the syntax
of printf-like format strings and can diagnose some errors -- but only
if the format string argument is a literal, and only for printf-like
functions.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 6 '08 #14
On Sat, 6 Sep 2008 12:30:27 -0700 (PDT), mdh <md**@comcast.netwrote:
>On Sep 6, 12:09*pm, Barry Schwarz <schwa...@dqel.comwrote:
snip
>As coded in K&R, minprintf will handle variadic arguments (the ones
implied by the ...) of type int, double, and char* based on the
conversion specification in the format string.

If you change the parameter and argument to an int, how will minprintf
know the type of the next argument to extract? *

Well...that is what I am clearly not getting. I **thought** that the
essence of the ellipse ( ...) was that one does not know what the type
and number of the arguments is?
>How will it know how many arguments to extract? *

Are you saying that the role of the declaration "char *fmt" is to
tell the compiler that each argument needs to be extracted as a char?
No, it does not tell the compiler (though there are some that will
check in the case of standard library functions). It tells the
function being called. (That is why you see messages in this group
that describe undefined behavior when someone passes an argument that
is incompatible with the conversion specification.) Look at the code
on page 156 again. If the conversion specification is %d, then the
code extracts an int. If it is %f, the code extracts a double. If it
is %s, the code extracts a char*. This all happens at run time, not
compile time.

The role of the char *fmt argument is to allow the same function to
handle different types and numbers of arguments. Why do you think
these functions are called variadic? A "regular" function must always
be called with the correct (or compatible) argument types and the
proper number of arguments. The printf and scanf families of
functions are two in the standard library that don't have this
requirement. minprintf is an example of how you could code your own
flexible function.

Now, show us your code (the one with the first parameter declared as
an int) so we can explain what you are doing wrong, even if it is only
misinterpreting what you see in the debugger.

--
Remove del for email
Sep 6 '08 #15
mdh
On Sep 6, 1:10 pm, Harald van Dk <true...@gmail.comwrote:
>

Then, please post a minimal complete program that includes the declaration
void minprintf(int fmt, ...);, defines that function exactly the way you
have defined it now, and calls it.

I have been trying to do so for a few hours, but each time I have been
called away! I will try and answer Barry Schwartz if not called again.
Sep 7 '08 #16
mdh
On Sep 6, 1:23*pm, Richard Heathfield <r...@see.sig.invalidwrote:
mdh said:

<snip>
May I pursue another issue a little further.
K&R (p 155) declare minprintf thus:
void minprintf(char *fmt, ...);
When I followed the example, it did not seem to matter to the output
whether the declaration was
void minprintf(char *fmt, ...);
or
void minprintf(int fmt, ...);

If I just change the declaration to suit yours, my compiler issues a
diagnostic message:

foo.c:7: conflicting types for `minprintf'
>
and halts the compilation.

as do I
>
If I change the declaration /and/ the definition, I get a different
diagnostic message:

foo.c:36: warning: passing arg 1 of `minprintf' makes integer from pointer
without a cast
same
>
Can you convince me that these diagnostic messages have no significance?


Richard...I would not even try!!! :-)
I will try and answer BS with an example.
Sep 7 '08 #17
mdh said:
On Sep 6, 1:23 pm, Richard Heathfield <r...@see.sig.invalidwrote:
<snip>
>Can you convince me that these diagnostic messages have no significance?

Richard...I would not even try!!! :-)
The point I am making is this: diagnostic messages are issued for a
*reason*.

Now, it is true that, on occasion, the compiler will issue a diagnostic
message even though the code is fine as it is, in much the same way that
you might see a "Caution - vehicles turning" sign whilst out driving, but
visibility is good and there are no blind corners and you can see that
there aren't any vehicles around of any kind, turning or otherwise - so
you can safely put your foot down despite the sign, BECAUSE you understood
the sign, understood its intent, and made a rational decision based on
your knowledge of prevailing conditions.

But, to extend the driving analogy a little further, you would be foolish
indeed to ignore a sign that warns you to take the next blind corner
slowly, yes? Most warning road signs are there for excellent reasons that
apply all or nearly all the time, and a responsible driver will adjust his
driving in keeping with the directions given by the signs.

Similarly, unless you are ASTOUNDINGLY sure that a compiler's diagnostic
message is spurious or, for some excellent reason that you fully
understand, not relevant, you ought to fix your code to get rid of the
message. To do that, you have to understand the message. (For example, the
message "initialization makes pointer from integer without a cast" does
NOT necessarily mean that a cast is the right way to get rid of the
message. It may instead mean that you're missing a header.)

Once you have understood the message, you should fix your code
appropriately, and recompile.
I will try and answer BS with an example.
That won't be necessary if you have properly learned your lesson, i.e. that
you cannot interchange char * and int with carefree abandon just because
you can get it to scrape through compilation.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 7 '08 #18
mdh
On Sep 6, 4:08*pm, Barry Schwarz <schwa...@dqel.comwrote:
On Sat, 6 Sep 2008 12:30:27 -0700 (PDT), mdh <m...@comcast.netwrote:
On Sep 6, 12:09*pm, Barry Schwarz <schwa...@dqel.comwrote:

snip
>
Are you saying that the role of the declaration *"char *fmt" *is to
tell the compiler that each argument needs to be extracted as a char?

No, it does not tell the compiler (though there are some that will
check in the case of standard library functions). *It tells the
function being called. *(That is why you see messages in this group
that describe undefined behavior when someone passes an argument that
is incompatible with the conversion specification.) *Look at the code
on page 156 again. *If the conversion specification is %d, then the
code extracts an int. *If it is %f, the code extracts a double. *If it
is %s, the code extracts a char*. *This all happens at run time, not
compile time.

The role of the char *fmt argument is to allow the same function to
handle different types and numbers of arguments.
..Please see below.

>*Why do you think
these functions are called variadic?
Wikipedia:"In computer programming, a variadic function is a function
of variable arity; that is, one which can take different numbers of
arguments."

I think they left out "and of different types".

>
Now, show us your code (the one with the first parameter declared as
an int) so we can explain what you are doing wrong, even if it is only
misinterpreting what you see in the debugger.
#include <stdio.h>
#include <stdarg.h>

int main (int argc, const char * argv[]) {
/*void minprintf(char *fmt, ...);*/
void minprintf(int fmt, ...);

minprintf("This is a test:\n%d:\n%s:\n%f:\n", 27, "More test",
-90.786);

/*warning: passing argument 1 of minprintf of incompatible pointer
type ( int fmt) */

return 0;
}

void minprintf(int fmt, ...)
/*void minprintf(char *fmt, ...)*/{

/* the role of char *fmt has been explained, but in 2 somewhat
different ways. Keith says "The *only* thing the "char *fmt, ..." part
of the declaration tells the compiler is that the first argument is of
type char*, and there
will be zero or more arguments of unspecified type(s) following that."
And Barry, you say that "The role of the char *fmt argument is to
allow the same function to handle different types and numbers of
arguments." Now my bet is that you are saying the same thing, but it
sounds somewhat different to me.

va_list ap;

/* So as Keith explained, ap is "an object type suitable for holding
information needed
by the macros va_start, va_arg, va_end, and va_copy" */

int ival;
double dval;
char *p, *sval;
va_start(ap, fmt);

/* So, here is the source of my confusion, and clearly the lack of
explaining it to the clc. I think this has been answered, so please
bear with me, but ap is now initialized to point to the first
unnamed argument. As Keith said "If the first argument were an int
rather than a char*, then minprintf wouldn't have any way of knowing
what argument values to grab." So I assume the initialization not only
points ap to the first argument, but it "types" the pointer as well,
and this information is conveyed by the expression "fmt". And,
rhetorically, I know the first argument is of type character, because,
""The *only* thing the "char *fmt, ..." part of the declaration tells
the compiler is that the first argument is of type char*" ( Keith).

For completeness,
debugger output (value of fmt) with declaration 'int fmt' =
1416128883 ( what I see in debugger as I step through the code)
debugger output (value of fmt) with declaration char *fmt = "This is
a test:\n%d:\n%s:\n%f:\n" ( as above)
debugger output (value of *ap) ( int fmt) = 0 '\0'
debugger output (value of *ap) ( char *fmt) = 0 '\0'

*/
for ( p=fmt; *p; p++){

/*So, the first argument, in my case "This is a test:\n%d:\n%s:\n%f:
\n" is now assigned to the char *p */

if ( *p != '%'){
putchar(*p);
continue;
}
switch (*++p) {
case 'd':
ival=va_arg(ap, int);

/* this part I get, I hope :-). Each call of va_arg returns 1 argument
and steps ap to the next argument but in addition, types ap correctly
for the expected value, in the above case, and integer*/

printf("%d", ival);
break;
case 'f':
dval=va_arg(ap, double);
printf("%f", dval);
break;
case 's':
for ( sval = va_arg(ap, char*); *sval; sval++)
putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
va_end(ap);
}
Sep 7 '08 #19
mdh
On Sep 6, 6:02*pm, Richard Heathfield <r...@see.sig.invalidwrote:
mdh said:
On Sep 6, 1:23 pm, Richard Heathfield <r...@see.sig.invalidwrote:

<snip>
Can you convince me that these diagnostic messages have no significance?
Richard...I would not even try!!! *:-)


Once you have understood the message, you should fix your code
appropriately, and recompile.

Hi Richard,
You convinced me **long ago** not to ignore warnings. I think what you
perhaps missed, not that I ignored the warning, but I am trying to
figure out **what** and **why** I am doing with some of the macros.
So, to take your car analogy, it would be like a newly emerged person
from the depths of the Amazon rain forest, who somehow got his license
in England (not sure how far we can stretch this) saying "Why is
there a sign about a blind corner and what's more, what is a blind
corner", and finding out the hard way there is a good reason for
it...and hopefully not becoming undefined in the process!.
Sep 7 '08 #20
mdh <md**@comcast.netwrites:
On Sep 6, 4:08*pm, Barry Schwarz <schwa...@dqel.comwrote:
[...]
>Now, show us your code (the one with the first parameter declared as
an int) so we can explain what you are doing wrong, even if it is only
misinterpreting what you see in the debugger.

#include <stdio.h>
#include <stdarg.h>

int main (int argc, const char * argv[]) {
/*void minprintf(char *fmt, ...);*/
void minprintf(int fmt, ...);

minprintf("This is a test:\n%d:\n%s:\n%f:\n", 27, "More test",
-90.786);

/*warning: passing argument 1 of minprintf of incompatible pointer
This warning has nothing to do with the fact that minprintf is
variadic (i.e., has a ", ..." in its declaration). You declared a
function whose first parameter is of type int, and you called it with
a first argument of type char*.
type ( int fmt) */

return 0;
}

void minprintf(int fmt, ...)
/*void minprintf(char *fmt, ...)*/{

/* the role of char *fmt has been explained, but in 2 somewhat
different ways. Keith says "The *only* thing the "char *fmt, ..." part
of the declaration tells the compiler is that the first argument is of
type char*, and there
will be zero or more arguments of unspecified type(s) following that."
And Barry, you say that "The role of the char *fmt argument is to
allow the same function to handle different types and numbers of
arguments." Now my bet is that you are saying the same thing, but it
sounds somewhat different to me.
We're saying two quite different things, both of them true.

I told you what information "char *fmt, ..." conveys *to the
compiler*. If you call minprintf with a first argument of type char*,
and zero or more additional arguments of any type you like, the
compiler won't complain, because you haven't given it enough
information to do so.

Barry told you the *purpose*, in the sense of the program logic, of
the "char *fmt" parameter. Its purpose is to point to a string that
encodes the intended number and type(s) of the following arguments.
The compiler knows nothing about its purpose; it knows only what it
is.

A variadic function has no direct way to determine the number and
type(s) of any arguments corresponding to the "..." in the prototype
-- and yet it must execute just the right sequence of va_arg calls to
extract the values of those arguments. That means it has to have some
indirect way to determine that information. One common method is to
encode the information in a format string. Other methods are
possible.

[snip]

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 7 '08 #21
mdh said:

<snip>
/*void minprintf(char *fmt, ...)*/{

/* the role of char *fmt has been explained, but in 2 somewhat
different ways. Keith says "The *only* thing the "char *fmt, ..." part
of the declaration tells the compiler is that the first argument is of
type char*, and there
will be zero or more arguments of unspecified type(s) following that."
And Barry, you say that "The role of the char *fmt argument is to
allow the same function to handle different types and numbers of
arguments." Now my bet is that you are saying the same thing, but it
sounds somewhat different to me.
They are saying different things, but both are correct. That is, one is
telling you about elephants in general, and the other is telling you about
this specific elephant.

What Keith is telling you (assuming you've quoted him correctly, which I
haven't checked - I'll trust you on that) is how the C compiler
understands the (char *fmt, ...) stuff. It sees char *, and thinks "Aha, a
pointer to char", sees fmt, and thinks "okay, I know its name now", sees
...., and thinks "whoa, variadic function, okay, no problem, I remember how
to do those"). It hasn't a clue what you're trying to do, what problem
you're trying to solve, so it has no idea whether char * is the type you
need or not.

What Barry is telling you is *why* bwk chose to use a char * for the first
argument - that is, he's explaining the purpose of fmt within the context
of this particular example function.

<snip>
va_start(ap, fmt);

/* So, here is the source of my confusion, and clearly the lack of
explaining it to the clc. I think this has been answered, so please
bear with me, but ap is now initialized to point to the first
unnamed argument. As Keith said "If the first argument were an int
rather than a char*, then minprintf wouldn't have any way of knowing
what argument values to grab." So I assume the initialization not only
points ap to the first argument, but it "types" the pointer as well,
and this information is conveyed by the expression "fmt".
No. You hand va_start the name of the last named parameter, the one that
occurs just before the ... bit, and it uses that information to get ready
to find (at RUNtime) the first unnamed argument value that has been passed
to this particular function. It doesn't actually find anything - not yet -
but it's ready when you are.

When you call va_arg(), you are telling the compiler that (a) you know
there's another argument to collect, and (b) you know its type. How do you
get that information, given that you can't see the calling function?
Answer: you establish a protocol, a contract, between the variadic
function and its caller. The protocol for minprintf is this: print all the
characters that you find in the fmt string, literally - UNLESS you
encounter a %s, a %d, or a %f. If you do encounter any of those, use
va_arg to obtain a char *, an int, or a double, respectively.

And,
rhetorically, I know the first argument is of type character, because,
""The *only* thing the "char *fmt, ..." part of the declaration tells
the compiler is that the first argument is of type char*" ( Keith).
No, the first parameter not only need not be of type character (by which I
presume you mean type char) but *is not* of that type. Keith is referring
to fmt itself, which is of type char *, not type char. The types of
subsequent parameters are unknown, so you have to work them out yourself.
The way minprintf does that is by using the fmt string. That isn't the
only way you could do it, but it's a very popular way.
For completeness,
debugger output (value of fmt) with declaration 'int fmt' =
Forget it. That isn't completeness. That's complete nonsense. Sorry, but
it's true - you can't just go round arbitrarily replacing syntax in the
wild hope that it might be meaningful.

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 7 '08 #22
mdh <md**@comcast.netwrites:
On Sep 6, 4:08*pm, Barry Schwarz <schwa...@dqel.comwrote:
<snip>
>>*Why do you think
these functions are called variadic?

Wikipedia:"In computer programming, a variadic function is a function
of variable arity; that is, one which can take different numbers of
arguments."

I think they left out "and of different types".
I'd leave it out too. A function that took a variable number of
arguments that all had to be of the same type would still be variadic
and one that always took the same number would not be variadic even if
they could be of different types in different calls (that would be
polymorphic). In other words, the types of the arguments have nothing
to do with the function being (or not being) variadic.

Of course in C a variadic function can take arguments of any type as
well as of any number (provided then required arguments are given).

--
Ben.
Sep 7 '08 #23
mdh
On Sep 6, 6:40*pm, Keith Thompson <ks...@mib.orgwrote:
mdh <m...@comcast.netwrites:
On Sep 6, 4:08*pm, Barry Schwarz <schwa...@dqel.comwrote:
[...]
Now, show us your code (the one with the first parameter declared as
an int) so we can explain what you are doing wrong, even if it is only
misinterpreting what you see in the debugger.
/*warning: passing argument 1 of minprintf of incompatible pointer

This warning has nothing to do with the fact that minprintf is
variadic (i.e., has a ", ..." in its declaration).
Was just trying to respond to the request of showing the code and
debugger information as fully as possible, without drawing any
inference from that.
>
type ( int fmt) */
*return 0;
}
void minprintf(int fmt, ...)
/*void minprintf(char *fmt, ...)*/{
/* the role of char *fmt has been explained, but in 2 somewhat
different ways. Keith says......
And Barry,......

We're saying two quite different things, both of them true.

I told you what information "char *fmt, ..." conveys *to the
compiler*. *If you call minprintf with a first argument of type char*,
and zero or more additional arguments of any type you like, the
compiler won't complain, because you haven't given it enough
information to do so.

Barry told you the *purpose*, in the sense of the program logic, of
the "char *fmt" parameter. *Its purpose is to point to a string that
encodes the intended number and type(s) of the following arguments.
The compiler knows nothing about its purpose; it knows only what it
is.

A variadic function has no direct way to determine the number and
type(s) of any arguments corresponding to the
>snip
>One common method is to
encode the information in a format string. *Other methods are
possible.
Thanks Keith for sticking with me. What I was trying to do was to
relate the "char *fmt", to the "..." and I finally, hopefully, get it,
thanks to your gentle persistence!!!!! :-)
Sep 7 '08 #24
mdh
On Sep 6, 6:50*pm, Richard Heathfield <r...@see.sig.invalidwrote:
mdh said:

<snip>
/*void minprintf(char *fmt, ...)*/{
/* the role of char *fmt has been explained, but in 2 somewhat
different ways. Keith says ....
And Barry, ....

They are saying different things, but both are correct....

>
What Keith is telling you .... is how the C compiler
understands the (char *fmt, ...) stuff. It sees char *, and thinks "Aha, a
pointer to char", sees fmt, and thinks "okay, I know its name now", sees
..., and thinks "whoa, variadic function, okay, no problem, I remember how
to do those"). It hasn't a clue what you're trying to do...

Well, in that respect, the compiler and I share something in
common!!!! :-) Seriously, you have very accurately articulated what I
have ignored up to now.

>
What Barry is telling you is *why* bwk chose to use a char * for the first
argument - that is, he's explaining the purpose of fmt within the context
of this particular example function.
Yep..got it.
>
So I assume the initialization not only
points ap to the first argument, but it "types" the pointer as well,
and this information is conveyed by the expression "fmt".

No. You hand va_start the name of the last named parameter, the one that
occurs just before the ... bit, and it uses that information to get ready
to find (at RUNtime) the first unnamed argument value that has been passed
to this particular function.
Ok...more clarity...thank you.
>
When you call va_arg(), you are telling the compiler that (a) you know
there's another argument to collect, and (b) you know its type.
snip
And,
rhetorically, I know the first argument is of type character, because,
""The *only* thing the "char *fmt, ..." part of the declaration tells
the compiler is that the first argument is of type char*" ( Keith).

. Keith is referring
to fmt itself, which is of type char *, ...... The types of
subsequent parameters are unknown, so you have to work them out yourself.

For completeness,
debugger output (value of *fmt) with declaration 'int fmt' =

Forget it. That isn't completeness. That's complete nonsense.

Richard, included trying to respond to the request "Now, show us your
code (the one with the first parameter declared as an int) so we can
explain what you are doing wrong, even if it is only misinterpreting
what you see in the debugger"

Richard and Keith...thanks so much for sticking with me. You have now,
hopefully, (until the next section at least) brought me one step
further away from being "undefined"! :-)
Sep 7 '08 #25
mdh
On Sep 6, 7:05*pm, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
mdh <m...@comcast.netwrites:
On Sep 6, 4:08*pm, Barry Schwarz <schwa...@dqel.comwrote:
<snip>
>*Why do you think
these functions are called variadic?
Wikipedia:"In computer programming, a variadic function is a function
of variable arity; that is, one which can take different numbers of
arguments."
I think they left out "and of different types".

I'd leave it out too. *A function that took a variable number of
arguments that all had to be of the same type would still be variadic
and one that always took the same number would not be variadic even if
they could be of different types in different calls (that would be
polymorphic). *In other words, the types of the arguments have nothing
to do with the function being (or not being) variadic.

Of course in C a variadic function can take arguments of any type as
well as of any number (provided then required arguments are given).

--
Ben.
Thanks Ben.
Sep 7 '08 #26
mdh wrote:
What I was trying to do was to
relate the "char *fmt", to the "..."
That's what va_list and va_start and va_end do.

--
pete
Sep 7 '08 #27
On Sat, 6 Sep 2008 18:16:07 -0700 (PDT), mdh <md**@comcast.netwrote:

>#include <stdio.h>
#include <stdarg.h>

int main (int argc, const char * argv[]) {
/*void minprintf(char *fmt, ...);*/
void minprintf(int fmt, ...);

minprintf("This is a test:\n%d:\n%s:\n%f:\n", 27, "More test",
-90.786);

/*warning: passing argument 1 of minprintf of incompatible pointer
type ( int fmt) */
And for some reason you think this can be ignored with impunity?
>
return 0;
}

void minprintf(int fmt, ...)
/*void minprintf(char *fmt, ...)*/{
unrelated commentary snipped
va_list ap;
ditto
int ival;
double dval;
char *p, *sval;
va_start(ap, fmt);

/* So, here is the source of my confusion, and clearly the lack of
explaining it to the clc. I think this has been answered, so please
bear with me, but ap is now initialized to point to the first
unnamed argument. As Keith said "If the first argument were an int
No, it points to the argument named format which should be the last
named argument.
>rather than a char*, then minprintf wouldn't have any way of knowing
what argument values to grab." So I assume the initialization not only
points ap to the first argument, but it "types" the pointer as well,
and this information is conveyed by the expression "fmt". And,
rhetorically, I know the first argument is of type character, because,
""The *only* thing the "char *fmt, ..." part of the declaration tells
the compiler is that the first argument is of type char*" ( Keith).

For completeness,
debugger output (value of fmt) with declaration 'int fmt' =
1416128883 ( what I see in debugger as I step through the code)
Since you have already invoked undefined behavior, the debugger output
is irrelevant.
>debugger output (value of fmt) with declaration char *fmt = "This is
a test:\n%d:\n%s:\n%f:\n" ( as above)
debugger output (value of *ap) ( int fmt) = 0 '\0'
debugger output (value of *ap) ( char *fmt) = 0 '\0'
On my system, va_list is conditionally defined as either a typedef for
a struct or a typedef for a char*. If it is the same on yours, the
attempting to display *ap in the debugger may not be meaningful.
>
*/
for ( p=fmt; *p; p++){
Didn't your compiler generate the mandatory diagnostic here also? Why
did you ignore it?
>
/*So, the first argument, in my case "This is a test:\n%d:\n%s:\n%f:
\n" is now assigned to the char *p */

if ( *p != '%'){
putchar(*p);
continue;
}
switch (*++p) {
case 'd':
ival=va_arg(ap, int);

/* this part I get, I hope :-). Each call of va_arg returns 1 argument
Since va_arg is not a function, you are not calling anything. Look up
your varargs.h and see the actual code that will be executed.
>and steps ap to the next argument but in addition, types ap correctly
for the expected value, in the above case, and integer*/

printf("%d", ival);
break;
case 'f':
dval=va_arg(ap, double);
printf("%f", dval);
break;
case 's':
for ( sval = va_arg(ap, char*); *sval; sval++)
putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
va_end(ap);
}
--
Remove del for email
Sep 7 '08 #28
Two minor nits.

Barry Schwarz said:
On Sat, 6 Sep 2008 18:16:07 -0700 (PDT), mdh <md**@comcast.netwrote:
<snip>
>>
/* So, here is the source of my confusion, and clearly the lack of
explaining it to the clc. I think this has been answered, so please
bear with me, but ap is now initialized to point to the first
unnamed argument. As Keith said "If the first argument were an int

No, it points to the argument named format which should be the last
named argument.
It's called fmt, not format.

<snip>
>>/* this part I get, I hope :-). Each call of va_arg returns 1 argument

Since va_arg is not a function, you are not calling anything. Look up
your varargs.h and see the actual code that will be executed.
stdarg.h, not varargs.h - and bear in mind that it needn't be a file to be
conforming, so it might not be viewable (and in any case it probably
wouldn't help him to get so involved in platform-specific stuff).

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 7 '08 #29
mdh
On Sep 7, 1:04*am, Barry Schwarz <schwa...@dqel.comwrote:
On Sat, 6 Sep 2008 18:16:07 -0700 (PDT), mdh <m...@comcast.netwrote:

/*warning: passing argument 1 of minprintf of incompatible pointer
type ( int fmt) */

And for some reason you think this can be ignored with impunity?

Barry...come on! Of course I don't think this can be ignored with
impunity. I think I can explain your incredulousness. You are
**rightly** concerned with writing correct code. But you **also**
understand **why** it is correct. Now imagine if I just corrected
something without **understanding** why it is correct. The code would
be correct, but I would be back next week making the same
error...well, that's the way I work. I obviously asked in such a way
that it was not obvious what I was trying to understand...but
eventually, thanks to you and others who stuck with me...I understand
the concept. In **trying** to understand the concept, I often find it
helpful to understand **why** something is wrong. Does that make
sense?

Let me just say that despite what you may think, I pay really close
attention to what you, and the others have to say. My only error is
perhaps to be persistent until I **get** it. If this comes across as
ignoring the obvious, or not giving heed to what you say, that is not
my intention.
Sep 7 '08 #30
mdh said:
On Sep 6, 6:02 pm, Richard Heathfield <r...@see.sig.invalidwrote:
<snip>
>Once you have understood the message, you should fix your code
appropriately, and recompile.


Hi Richard,
You convinced me **long ago** not to ignore warnings. I think what you
perhaps missed, not that I ignored the warning, but I am trying to
figure out **what** and **why** I am doing with some of the macros.
So, to take your car analogy, it would be like a newly emerged person
from the depths of the Amazon rain forest, who somehow got his license
in England (not sure how far we can stretch this) saying "Why is
there a sign about a blind corner and what's more, what is a blind
corner", and finding out the hard way there is a good reason for
it...and hopefully not becoming undefined in the process!.
In this case, it's more like:

Me: "Drive on the left."
You: "Okay, I'll try driving on the right and see what happens."
Me: "Your funeral, not mine."

I understand your desire to grasp the mechanism behind the va macros. On
most machines, it's pretty simple really - va_list simply keeps track of
the first unused argument. When you call va_arg, telling it the type of
the argument, it yields the argument value and, as a side effect, updates
va_list by the right number of bytes to point to the /next/ argument.

But you don't actually need to know that to write C programs, and in fact
it's better (from a portability perspective) if you *don't* know, or if
you can at least pretend you don't know - because it might work
differently on a different machine.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 7 '08 #31
On Sun, 7 Sep 2008 01:46:27 -0700 (PDT), mdh <md**@comcast.netwrote:
>On Sep 7, 1:04*am, Barry Schwarz <schwa...@dqel.comwrote:
>On Sat, 6 Sep 2008 18:16:07 -0700 (PDT), mdh <m...@comcast.netwrote:
>
/*warning: passing argument 1 of minprintf of incompatible pointer
type ( int fmt) */

And for some reason you think this can be ignored with impunity?


Barry...come on! Of course I don't think this can be ignored with
impunity. I think I can explain your incredulousness. You are
But you executed code that did not compile correctly. Then you asked
why it appeared to work anyway and why your debugger showed something
you didn't expect. In this situation, the only way to get a
reasonable answer to those questions (ignoring whether the questions
are worth asking) is in a group that discusses your system. We can
tell you the behavior is undefined but we cannot tell you why your
debugger showed something (anything?) or why the code seemed to do
what you expected.
>**rightly** concerned with writing correct code. But you **also**
understand **why** it is correct. Now imagine if I just corrected
something without **understanding** why it is correct. The code would
You mean that at this stage you still don't understand that the
arguments you pass to a function must match the parameters the
function expects? Ignore the why. Treat it as a language
restriction, no different than defining variables before using them or
only coding executable statements inside a function.
>be correct, but I would be back next week making the same
error...well, that's the way I work. I obviously asked in such a way
that it was not obvious what I was trying to understand...but
eventually, thanks to you and others who stuck with me...I understand
the concept. In **trying** to understand the concept, I often find it
helpful to understand **why** something is wrong. Does that make
sense?
There are way too many wrong things to worry about **why** each is
wrong. You cannot add two pointers, you cannot multiply a pointer by
an integer, you cannot convert a pointer to a different type without
taking alignment into consideration, you can pass NULL to free but not
to getc, you can initialize an automatic variable with the result of a
function call but not a static variable, and on and on.

--
Remove del for email
Sep 7 '08 #32
mdh
On Sep 7, 10:57*am, Richard Heathfield <r...@see.sig.invalidwrote:
mdh said:
On Sep 6, 6:02 pm, Richard Heathfield <r...@see.sig.invalidwrote:

<snip>
Once you have understood the message, you should fix your code
appropriately, and recompile.
Hi Richard,
You convinced me **long ago** not to ignore warnings..

In this case, it's more like:

Me: "Drive on the left."
You: "Okay, I'll try driving on the right and see what happens."
Me: "Your funeral, not mine."
>
But you don't actually need to know that to write C programs, and in fact
it's better (from a portability perspective) if you *don't* know, or if
you can at least pretend you don't know - because it might work
differently on a different machine.

Richard...thanks for being so patient. I took a good look at a lot of
the discussions over the years in the clc...as I had plenty of time
last night! One thing I realized was that "undefined behavior" has
come up ad nauseum and, understandably, the gusto to explain each time
that once ub occurs...all discussion ends. So I can see how some of my
questions must frustrate sometimes, esp falling into the trap of
trying to discern why something is not working by looking at a result
after ub has occurred. Having said that, it does lead me to ask you
this.
If one sees a diagnostic ( and I specifically mean a warning) , should
I, as you newbie ( not you as the expert) assume that anything after
this is ub ( as far as I can see, a message does not actually use the
term 'ub'), and as such, my questions ought to be directed, if any to
the cause of the diagnostic, as opposed to the result. I think this is
the error I made in this line of questioning, esp when asked to show
code.
Sep 7 '08 #33
Barry Schwarz <sc******@dqel.comwrites:
On Sun, 7 Sep 2008 01:46:27 -0700 (PDT), mdh <md**@comcast.netwrote:
>>On Sep 7, 1:04*am, Barry Schwarz <schwa...@dqel.comwrote:
>>On Sat, 6 Sep 2008 18:16:07 -0700 (PDT), mdh <m...@comcast.netwrote:

/*warning: passing argument 1 of minprintf of incompatible pointer
type ( int fmt) */

And for some reason you think this can be ignored with impunity?


Barry...come on! Of course I don't think this can be ignored with
impunity. I think I can explain your incredulousness. You are

But you executed code that did not compile correctly. Then you asked
why it appeared to work anyway and why your debugger showed something
you didn't expect. In this situation, the only way to get a
reasonable answer to those questions (ignoring whether the questions
are worth asking) is in a group that discusses your system. We can
tell you the behavior is undefined but we cannot tell you why your
debugger showed something (anything?) or why the code seemed to do
what you expected.
Nonsense. Someone will be able to. Possibly there are more people here
using his platform because they are interested in C than populate the
"for that platform group".

So less of the "we".

The reason was, in fact, explained to him in this very thread.

And such practical examples, when contrasted with the mythical systems
we keep hearing of here, make great strides in convincing people WHY
"standard C" is better. It's just a pity too many of you run off and
hide behind the "we" and "off topic" rather than compare and contrast
REAL systems in the Standard C arena. Now *that* would be helpful to
people. Real people. With real compilers and platforms. And real
deadlines. And real issues.

Sep 7 '08 #34
mdh
On Sep 7, 11:20*am, Barry Schwarz <schwa...@dqel.comwrote:
**understanding** why it is correct. The code would

You mean that at this stage you still don't understand that the
arguments you pass to a function must match the parameters the
function expects?

Barry, I appreciate all the help you have given. As to the specific
question above, I have to defend myself. I **thought** that the
arguments and parameters **did** match, as I conveniently ignored the
warning...which should be read as not quite understanding the
importance and gravity of ignoring a diagnostic. Hopefully, I will not
make that mistake again. However, if I ever do, I am sure it will be
pointed out again, with even greater gusto !! :-) ( see my answer
that I have just given to Richard, before I saw yours).
Sep 7 '08 #35
mdh <md**@comcast.netwrites:
On Sep 7, 11:20*am, Barry Schwarz <schwa...@dqel.comwrote:
>**understanding** why it is correct. The code would

You mean that at this stage you still don't understand that the
arguments you pass to a function must match the parameters the
function expects?


Barry, I appreciate all the help you have given. As to the specific
question above, I have to defend myself. I **thought** that the
arguments and parameters **did** match, as I conveniently ignored the
warning...which should be read as not quite understanding the
importance and gravity of ignoring a diagnostic.
Do you ignore road signs too?
Sep 7 '08 #36
On Sep 7, 7:33*pm, mdh <m...@comcast.netwrote:
On Sep 7, 10:57*am, Richard Heathfield <r...@see.sig.invalidwrote:
<snip>
Richard...thanks for being so patient. I took a good look at a lot of
the discussions over the years in the clc...as I had plenty of time
last night! One thing I realized was that "undefined behavior" has
come up ad nauseum and, understandably, the gusto to explain each time
that once ub occurs...all discussion ends. So I can see how some of my
questions must frustrate sometimes, esp falling into the trap of
trying to discern why something is not working by looking at a result
after ub has occurred. Having said that, it does lead me to ask you
this.
If one sees a diagnostic ( and I specifically mean a warning) , should
I, as you newbie ( not you as the expert) assume that anything after
this is ub ( as far as I can see, a message does not actually use the
term 'ub'),
sadly no :-(
implementations are permitted to output diagnostics
for anything they feel the whim to do so.

For instance "unused variable" is poor style but harmless
(unless you meant to use the variable!)

Some compilers complain if you don't use the return value
of a function. Again mostly harmless.

I'm afraid you just have to learn. Parameter mismatch
is one you can't usually ignore.

As a rule of thumb strive for a "clean compile", no errors
or warnings. Sadly this isn't always possible.

Try to understand what the compiler is trying to say and
then decide if you can live with it.
and as such, my questions ought to be directed, if any to
the cause of the diagnostic, as opposed to the result. I think this is
the error I made in this line of questioning, esp when asked to show
code
--
Nick Keighley
Sep 7 '08 #37
mdh wrote:
....
If one sees a diagnostic ( and I specifically mean a warning) , should
I, as you newbie ( not you as the expert) assume that anything after
this is ub ( as far as I can see, a message does not actually use the
term 'ub'), and as such, my questions ought to be directed, if any to
the cause of the diagnostic, as opposed to the result. I think this is
the error I made in this line of questioning, esp when asked to show
code.
It's a good rule of thumb that you should set your compiler to it's
most sensitive warning level, and write your code so that it doesn't
generate any warnings. Like most rules of thumb, you need to be
careful about applying this; some compilers will warn about a great
many things that they don't need to warn about - you should either
turn off those warnings, or ignore them. More importantly, unless you
understand why a warning message was issued, you can't be sure of the
correct way to fix it; some ways of turning off warnings don't do
anything about the actual problem; some ways even make it worse.

Unfortunately, as a newbie you have no easy way to distinguish between
legitimate warnings and unnecessary ones, between the right way to fix
something and the wrong way to fix it.. The hard way, which i strongly
recommend, is that you should always figure out why the warning is
being produced, before you make any decision about how to fix the
problem it's warning you about.
Sep 7 '08 #38
mdh said:

<snip>
If one sees a diagnostic ( and I specifically mean a warning) , should
I, as you newbie ( not you as the expert) assume that anything after
this is ub ( as far as I can see, a message does not actually use the
term 'ub'), and as such, my questions ought to be directed, if any to
the cause of the diagnostic, as opposed to the result.
Yes. If in doubt, assume that a diagnostic message indicates a problem with
your code that must be fixed before proceeding. To fix the code, you must
understand what the diagnostic message is telling you. As I suggested
earlier, this isn't always as obvious as we might like.

If in serious doubt, well, ask.

(Note that the *absence* of diagnostic messages is certainly not a
guarantee that all is well.)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 7 '08 #39
mdh
On Sep 7, 12:32*pm, jameskuy...@verizon.net wrote:
mdh wrote:

...
If one sees a diagnostic ( and I specifically mean a warning) , should
I, as you newbie ( not you as the expert) assume.......


Unfortunately, as a newbie you have no easy way to distinguish between
legitimate warnings and unnecessary ones,...... The hard way, which i strongly
recommend, is that you should always figure out why the warning is
being produced, before you make any decision about how to fix the
problem it's warning you about.

Well, Nick and James...that is the **strong** take home message from
this discussion for me. I think it will at the very least, serve to
focus the inquiry if I do ask the clc. Thank you both.
Sep 7 '08 #40
mdh wrote:
On Sep 7, 11:20�am, Barry Schwarz <schwa...@dqel.comwrote:
**understanding** why it is correct. The code would

You mean that at this stage you still don't understand that the
arguments you pass to a function must match the parameters the
function expects?


Barry, I appreciate all the help you have given. As to the specific
question above, I have to defend myself. I **thought** that the
arguments and parameters **did** match
I don't want you to feel as though we're harrassing you, but that's
the key part I've never understood about this thread, and it seems
that most of the other people are feeling similarly frustrated about
it. How did you reach the incorrect conclusion that they did match?
People make mistakes all the time, I'm certainly not an exception, but
I don't understand the nature of this particular mistake.

The first time we saw your actual code was in your message with
Date: Sat, 6 Sep 2008 18:16:07 -0700 (PDT)
In that message, your very own code showed a correct prototype for
minprintf() commented out, in which the first parameter was declared
as 'char *'. The very next line shows an incorrect prototype, not
commented out, which declared the first parameter as an 'int'. This
was followed by an actual call to the function with a first argument
of type char*. Finally, you include a comment that indicates that the
compiler gave you a warning indicating that the function call involved
an argument of a type that was incompatible with the type of the
corresponding parameter in your function prototype.

How could you modify the prototype without being aware of the fact
that your change would break your code? How could you see a compiler's
warning message that explained what the problem was, add a comment to
your code about that message, and yet remain unaware of the problem?
The only way this makes sense to me is if you thought that 'int' was
a synonym for 'char*', and I can't figure out what might have given
you that idea.
Sep 7 '08 #41
mdh
On Sep 7, 1:16 pm, jameskuy...@verizon.net wrote:
mdh wrote:
On Sep 7, 11:20 am, Barry Schwarz <schwa...@dqel.comwrote:
**understanding** why it is correct. The code would
You mean that at this stage you still don't understand that the
arguments you pass to a function must match the parameters the
function expects?
Barry, I appreciate all the help you have given. As to the specific
question above, I have to defend myself. I **thought** that the
arguments and parameters **did** match

I don't want you to feel as though we're harrassing you,

No...I have followed other threads and I do **not** feel harrassed.
I am at times equally frustrated at not being able to clearly
articulate my questions well.


>but that's
the key part I've never understood about this thread,

An honest question and I will attempt to answer it.

May I start with an analogy ( true, by the way). In 1992 12 of us
sailed from St Augustine in Florida to Lisbon. One of the crew was
Michael Smith. A year later, in 1993 he would get the Noble Prize in
Chemistry for his work in "oligonucleotide-based, site-directed
mutagenesis and its development for protein studies". As a graduate
he wanted to understand the configurations of protein. As we sat
around the breakfast table in the middle of the ocean, he would
explain how it worked. This is the analogy he ( or his s.o..can't
remember which) gave. Imagine that you have an engine. You have no
manual, but you develop a tool to open the engine, take something out,
and put it back together again. Then you fire up the engine and see
what happens. ( Instead of looking at engines, he was looking at the
way proteins folded). If you do this enough times, taking out
different bits each time, eventually you might be able to draw a
conclusion as to what the piece you removed did. That is often the way
I have approached things in my life....maybe not driving around blind
corners, but certainly in thought experiments etc.
Now...through the course of this thread, I realize that this cannot be
applied directly to C, because of one **small** issue, calle undefined
behavior :-) Whereas one might get a **predictably** **different**
response by pulling out bits and pieces from DNA or an engine,
deliberately doing so in C is different.

So, at the beginning of the thread, this is what I thought.

So, let me preface this by saying

****What I am about to write is wrong thinking***

If I do not understand something, (in C) by **deliberately** creating
an error, I can try and figure out, by looking at the result , how the
**original** expression/function/whatever works

****End of wrong thinking*****
*****Correct thinking*****

If one sees a diagnostic, it **could** mean ub, but in any case, **GO
NO FURTHER** until it is understood. The end result **should** be the
same ie in terms of understanding the issue, but it sure as heck won't
frustrate the clc the way this thread has done!!!!! :-)

**** End of hopefully correct thinking****

it. How did you reach the incorrect conclusion that they did match?
People make mistakes all the time, I'm certainly not an exception, but
I don't understand the nature of this particular mistake.

I hope the above explanation sheds some light on it. ( and see below)

>
The first time we saw your actual code was in your message with
Date: Sat, 6 Sep 2008 18:16:07 -0700 (PDT)
In that message, your very own code showed a correct prototype for
minprintf() commented out, in which the first parameter was declared
as 'char *'. The very next line shows an incorrect prototype,

James, originally I was going to just post the above and not answer
the specifics...but clearly you have taken the trouble to look back
through the thread, so the very least I can do is go back and show
what I was trying to ask, the relevant replies and hopefully clarify
this for you.
>
How could you modify the prototype without being aware of the fact
that your change would break your code? How could you see a compiler's
warning message that explained what the problem was, add a comment to
your code about that message, and yet remain unaware of the problem?
The only way this makes sense to me is if you thought that 'int' was
a synonym for 'char*', and I can't figure out what might have given
you that idea.
So, I hope this will answer some of your queries.

It all started off with a question about Macros.

Sept 5, 4:15pm (mdh) ( all times PDT)
>>>
The section is titled Variable-length Argument lists.
May I ask a question about the use of "macros".
Could anyone help me understand the significance of using macros vs
functions, as I think it is more significant than I realize.
<<<<<


5:20pm (KT) (Amongst others)
>>>>>>
The reason va_start, va_arg, va_end, and va_copy are defined as
macros
is that they *can't* be defined as functions.
For example, va_arg takes two arguments, an expression of type
va_list
(I'm actually not sure it can be an arbitrary expression) and a type
name.
<<<<<<<

Then I asked about clarification of the expression va_list ap.

6:43 pm (mdh)
>>>>>
This declares ap a pointer of type va_list? And the reason ap is a
pointer is simply because that is the way it is defined??
<<<<<


and again KT answered at 7:21pm
>>>>>>>
The standard merely says that it's "an object type suitable for
holding information needed
by the macros va_start, va_arg, va_end, and va_copy"
<<<<<<<<
There was some discussion as to why I thought what I thought, but that
was sorted out. The one thing that I could not put into context was
what the role of the "char *fmt" in the decalration "(char *fmt, ...)
was. I knew it was obviously important, in va_start.

Also at 6:43pm (mdh)
>>>>>>>>>
va_start(ap, fmt);
So, from what you say, if I understand this, the type here (fmt) is
"pointer to char" and the expression 'ap' is initialized or "returned"
as a pointer to char (to the first argument)?
<<<<<<<<<
And again, KT answered in the same reply at 7:21pm
>>>>>>>>>>>
va_start doesn't return anything. It initializes ap, an object of
type va_list. (That's part of the reason it's a macro; a function
can't modify an argument.) The va_list object exists to allow access
to the variadic arguments; you can think of it as a kind of abstract
index into the argument list.
The second argument to va_start is the name of the parameter just
before the ", ...".

<<<<<<<<<<<<<

After getting some sleep, I still could not understand the exact role
of "char *fmt", so the next day posted this...and this is where it all
started going downhill.

Sept 6, 11:46 am (mdh)
>>>>>>>>>>
May I pursue another issue a little further.

void minprintf(char *fmt, ...);
or
void minprintf(int fmt, ...);

The only difference is ( maybe the **only** will raise some chuckles)
that char *fmt points to all the arguments in my debugger, but int
returns an integer( surprise, surprise!). For fear of flogging a dead
horse, is that the difference?

<<<<<<<<<<

Clearly...in hindsight, this was ***WRONG THINKING*** !!!!!...but
that is where this came from. In addition, the use of the term
debugger muddied the water even further.

I think the clc gave me a little to much credit in thinking I
understood the gravity and significance of ub. At this point, a bunch
of different questions were posed, and I tried to be diligent in
answering them as best I could, including a plea for actual code.

BS at 12:09 pm
>>>>>>>>>>
Show your code for a minprintf with an int as its
first parameter and a sample calling statement.

<<<<<<<<<


HvD at 1:10pm
>>>>>>>>>
Then, please post a minimal complete program that includes the
declaration
void minprintf(int fmt, ...);, defines that function exactly the way you
have defined it now, and calls it.
<<<<<<<<<<<
Again, I tried to hone in on the one thing that was not making sense
to me.

mdh at 12:30pm
>>>>>>>>>
Are you saying that the role of the declaration "char *fmt" is to
tell the compiler that each argument needs to be extracted as a char?
<<<<<<<<<<<

RH ( who has been one of the stalwarts, in helping me navigate C)
quickly cut to the chase

RH at 1.23pm
>>>>>>>>>>>>
f I change the declaration /and/ the definition, I get a different
diagnostic message:
foo.c:36: warning: passing arg 1 of `minprintf' makes integer from
pointer
without a cast
Can you convince me that these diagnostic messages have no
significance?

<<<<<<<<<<<<

Again...**WRONG THINKING** on my part.
KT answered ( my 12:30pm query) at 4.02pm
>>>>>>>>>
The *only* thing the "char *fmt, ..." part of the declaration tells
the compiler is that the first argument is of type char*, and there
will be zero or more arguments of unspecified type(s) following that.
........

For example, if a call
looks like this:
minprintf("%s = %d\n", "foobar", 42);
then minprintf itself needs to make the following calls to fetch the
parameter values:
va_list ap;
va_start(ap, fmt);
va_arg(ap, char*);
va_arg(ap, int);
va_end(ap);

<<<<<<<<<<
That should have been the end of it, but there now seemed to be a
concurrent thread that had honed in on the **WRONG THINKING** part of
my replies ie trying to explain how diagnostics had been ignored, and
meaning given to ub.

At 6:03pm ( mdh) I posted the code I think you are referring to

>>>>>>>>
void minprintf(int fmt, ...)
/*void minprintf(char *fmt, ...)*/{

.....etc etc

<<<<<<<<<<

So James, I hope you understand now where that craziness came from. A
combination of **WRONG THINKING** and trying to diligently respond to
people trying to help me.

At some point, RH said.

RH at 6:50pm
>>>>>>
/* So, here is the source of my confusion,
You hand va_start the name of the last named parameter,
When you call va_arg(), you are telling the compiler that (a) you
know
there's another argument to collect, and (b) you know its type.

and

Keith is referring
to fmt itself, which is of type char *, not type char.

For completeness,
debugger output (value of fmt) with declaration 'int fmt' =
Forget it. That isn't completeness. That's complete nonsense.

<<<<<<<<<<<<<<<<
??*** :-) I won't make the "for completeness" mistake again!!!!


Hopefully, I have not lost BS forever!
BS at 11:20 am ( today)
>>>>>>>>>
But you executed code that did not compile correctly. Then you asked
why it appeared to work anyway and why your debugger showed something
you didn't expect.

<<<<<<<<<

I hope my earlier explanation covers this.
So James, I hope this does justice to all the time you have taken to
help. As I look through this thread, it's confusing to me too, at
times!!. Perhaps, it would have been more appropriate to start another
thread once the issues of the macros had been settled, as it **might**
have made it cleaner.
So, to all of the people who answered this thread, I am sorry if this
lead to frustration. One of the great joys is being part of the clc
and interacting with such amazing programmers. You have no idea
( well, maybe you do) how stimulating this is.
So thank you and ....
This is a learning curve to me too.
Sep 8 '08 #42
mdh wrote:
Imagine that you have an engine.
You have no manual,
That's where the analogy breaks.
but you develop a tool to open the engine, take something out,
and put it back together again. Then you fire up the engine and see
what happens. ( Instead of looking at engines, he was looking at the
way proteins folded). If you do this enough times, taking out
different bits each time, eventually you might be able to draw a
conclusion as to what the piece you removed did. That is often the way
I have approached things in my life....maybe not driving around blind
corners, but certainly in thought experiments etc.
http://www.google.com/search?hl=en&q...22&btnG=Search

Results 1 - 10 of about 20,000 for
"If all else fails, read the instructions".

--
pete
Sep 8 '08 #43
mdh said:

<snip>
As a graduate
he wanted to understand the configurations of protein. As we sat
around the breakfast table in the middle of the ocean, he would
explain how it worked. This is the analogy he ( or his s.o..can't
remember which) gave. Imagine that you have an engine. You have no
manual, but you develop a tool to open the engine, take something out,
and put it back together again. Then you fire up the engine and see
what happens. ( Instead of looking at engines, he was looking at the
way proteins folded).
As a graduate, he would have been about 20 years old - about 1952 or so -
and that would have been about the only way to work stuff out about
protein-folding, and it would have taken a LONG time. Nowadays, people can
build on the knowledge he and others gained, so there /is/ a manual of
sorts. The technique you describe is one for pioneers, not engineers.

C is a known language designed by human beings, not a natural phenomenon
into which we need to do research. The rules are clearly understood by a
great many people (and less clearly understood by a great many more,
largely because they use something similar to the technique you suggest of
ignoring the manual and the experts in favour of random experimentation).

You will progress a lot more quickly if you understand that C is not a
natural phenomenon but something designed by people. Since it is designed
to suit many different kinds of hardware, it is deliberately designed in a
fairly abstract way, but not /so/ abstract that it becomes clunky and
inefficient. I suggest you focus, for now, on learning how to write C for
that abstract machine. (You don't need to find a weird "abstract machine
compiler" for this - a program that successfully addresses the abstract
machine will work on any compiler on any platform, and in fact that's the
whole point.)

When you start unplugging good code and plugging in bad "to see what
happens", it's like tossing a million dice and then trying to work out why
they don't show the base-6 encoding of pi.

If you do this enough times, taking out
different bits each time, eventually you might be able to draw a
conclusion as to what the piece you removed did.
Yes, and if you don't have a manual, that may be the only way to proceed -
and it might take you several lifetimes to get anywhere useful. Do you
have that amount of time available to you? (And in case I didn't make it
obvious enough, that's a rhetorical question.)

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 8 '08 #44
mdh
On Sep 7, 11:02*pm, Richard Heathfield <r...@see.sig.invalidwrote:
mdh said:

<snip>
As a graduate
he wanted to understand the configurations of protein.
<snip>

As a graduate, he would have been about 20 years old - about 1952 or so -
and that would have been about the only way to work stuff out about
protein-folding, and it would have taken a LONG time. Nowadays, people can
build on the knowledge he and others gained,

Richard...thank you. I am agreeing with you. The reason I wrote that
long response was that James, who like you has always been responsive
to my questions, had taken the trouble to go back and try and figure
out what I had been mis-understanding. The very least I could do was
try and give him an answer showing the evolution of my **new**
understanding.

(What I had not quite connected was the **gravity** and
**significance** of diagnostics and **potential** ub. I was not trying
to ignore the "manual", but merely trying to understand it. :-)
Richard...just think how boring it would be if everyone thought
exactly the same way!!!! :-) :-)
Sep 8 '08 #45
Richard Heathfield wrote:
>
.... snip ...
>
C is a known language designed by human beings, not a natural
phenomenon into which we need to do research. The rules are
clearly understood by a great many people (and less clearly
understood by a great many more, largely because they use
something similar to the technique you suggest of ignoring the
manual and the experts in favour of random experimentation).
Not to mention the erroneious information they 'learn' because of
the use of an erroneous compilation system.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Sep 8 '08 #46

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

6 posts views Thread by Dimitri Tholen | last post: by
reply views Thread by Thomas Scheffler | last post: by
16 posts views Thread by TTroy | last post: by
6 posts views Thread by MPH Computers | last post: by
4 posts views Thread by Antnio Pinho | last post: by
6 posts views Thread by Mike Moore | last post: by
7 posts views Thread by Ioannis Vranos | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by kglaser89 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.