473,721 Members | 2,234 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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.hcontai ns 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
45 1995
mdh <md**@comcast.n etwrites:
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
misinterpretin g 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_Keit h) 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.n etwrites:
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.orgw rote:
mdh <m...@comcast.n etwrites:
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.i nvalidwrote:
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.n etwrites:
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.n etwrote:

>#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.n etwrote:
<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.n etwrote:

/*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...bu t
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

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

Similar topics

3
6004
by: wenke | last post by:
Hi, I am using the following code (see below) from php.net (http://www.php.net/manual/en/ref.xml.php, example 1) to parse an XML file (encoded in UTF-8). I changed the code slightly so that the cdata sections will be echoed an not the element names as in the original example. In the cdata sections of my XML file I have terms like this:
6
15498
by: Dimitri Tholen | last post by:
Hi all, For a project I m working on I am looking for a database with all current car-makes & models from post-WII till now. With all the car websites around I am sure this information should be available somewhere so that I can import it into my MySQL database, but I simply can't find it. Does anybody know where I can get my hands on "a" database with this
0
2421
by: Thomas Scheffler | last post by:
Hi, I runned in trouble using XALAN for XSL-Transformation. The following snipplet show what I mean: <a href="http://blah.com/?test=test&amp;test2=test2">Test1&amp;</a> <a href="http://blah.com/?test=test&amp;amp;test2=test2">Test2&amp;amp;</a> This results in the following HTML Code:
4
2811
by: MLH | last post by:
A programmer developed an AMP (Apache/MySQL/PHP) application for me. When he was done, he sent me the PHP files and the MySQL dump file. Now, when I connect to the application on my LAN using http://192.168.1.106/~mlh/credifree/index.php the AMP app still thinks the data resides somewhere else. It runs fine - as long as I leave my LAN's external internet connection up. But if I unplug my LAN from the world, my app locks up. Before I...
16
1679
by: TTroy | last post by:
I FOUND MAJOR ERRORS in K&R2 (making it almost useless for the herein mentioned topics). K&R2 Section 5.9 Pointers vs. Multidimension Arrays starts of like this... "Newcomers to C are somtimes confused about the difference between a two-dimensional array and an array of pointers..." then continues to explain int *b; to be...
6
3261
by: MPH Computers | last post by:
Hi I am looking for some help on Threading and Critical Sections I have a main thread that controls an event the event handler creates a new thread for carrying out the work because the work may not be completed before the event is triggered again I am trying to add critical sections round the producer & consumer parts of
4
1873
by: António Pinho | last post by:
Hi, I have a big problem with an webpart/assembly. i'm trying to connect to sql server but i get the error "Request for the permission of type System.Data.SqlClient.SqlClientPermission, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.". i've searched for it and can't find a clear answer. but one thing i'm sure: permissions. if i change the trust level in the web.config of the sharepoint portal...
6
2562
by: Mike Moore | last post by:
I'm not very familiar with the web config file. I would like to use the timeout item in the session state for our connection string, but not use the stateconnection string and sqlconnectionstring in the sessionstate section. I have our connection string information in the appsettings section of the web config file. Our authenication mode reads - <authentication mode="Windows" /> <identity impersonate="true" />
1
3474
by: Andrew Wan | last post by:
How can VBScript code access JScript code variables in the same ASP page? <SCRIPT LANGAUGE="VBScript"> Dim a a = 10 </SCRIPT> <SCRIPT LANGUAGE="JScript"> Response.Write(a); </SCRIPT>
7
185
by: Ioannis Vranos | last post by:
In K&R2 errata page <http://www-db-out.research.bell-labs.com/cm/cs/cbook/2ediffs.html> there are some ambiguous errata, for which I propose solutions. Any comments are welcome. Ambiguous errata (mentioned first) of "The C Programming Language" 2nd Edition errata page (http://www-db-out.research.bell-labs.com/cm/cs/cbook/2ediffs.html), and
0
8730
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9367
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9215
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9131
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9064
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8007
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5981
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4753
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2576
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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

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