variable arguments question

A

Alessio

Hi,

I've two questiond regarding variable arguments.
First, how to count arguments passed ?
I see that va_arg macro can be used, but if don't know type of
arguments ?

Then, How can a print a % sign with vsnprintf ?
Please consider this code:

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

//
#define BUFFER_SIZE 256

//
void myPrintf(char *szText, ...)
{
char szBuffer[BUFFER_SIZE] = { 0 };
va_list pArgList = NULL;

va_start(pArgList, szText);
vsnprintf(szBuffer, BUFFER_SIZE, szText, pArgList);
va_end(pArgList);

printf(szBuffer);
}

//
int main(void)
{
myPrintf("this string should show a %% (percent sign)\n");

return 0;
}

on my windows box using PellesC, Gcc, Tcc and Vc++ i get:

this string should show a (percent sign)

as you can see % sign is not present, with Lcc I get an empty string.

Thank you,
Alessio.
 
E

Eric Sosman

Alessio said:
Hi,

I've two questiond regarding variable arguments.
First, how to count arguments passed ?

The <stdarg.h> mechanisms provide no way to do this.
You need to deduce the number and type(s) of the variable
arguments by examining something else, often something in
the fixed arguments. The printf() function[*], for example,
uses its format string to figure out what the other arguments
are. Or if you know the types of the variable arguments
(all `int', say), you might just keep retrieving them until
you come to an argument with an agreed-upon special value,
like zero or negative one or something that makes no sense
as a "real" value.

[*] Since it's a part of the implementation, the printf()
function might use some kind of implementation-specific
trickery rather than actually using <stdarg.h> -- it might
I see that va_arg macro can be used, but if don't know type of
arguments ?

You *must* know the type of an argument *before* you try
to retrieve it with va_arg(), because you must tell va_arg()
what kind of value it is supposed to retrieve.
Then, How can a print a % sign with vsnprintf ?

With "%%" in the format string.
Please consider this code:

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

//
#define BUFFER_SIZE 256

//
void myPrintf(char *szText, ...)
{
char szBuffer[BUFFER_SIZE] = { 0 };
va_list pArgList = NULL;

va_start(pArgList, szText);
vsnprintf(szBuffer, BUFFER_SIZE, szText, pArgList);
va_end(pArgList);

printf(szBuffer);
}

//
int main(void)
{
myPrintf("this string should show a %% (percent sign)\n");

return 0;
}

on my windows box using PellesC, Gcc, Tcc and Vc++ i get:

this string should show a (percent sign)

as you can see % sign is not present, with Lcc I get an empty string.

vsnprintf() finds the "%%" in the format string, and
deposits a single '%' in szBuffer. Then you hand szBuffer
to printf() *as a format string*. printf() sees the lone
'%' sitting there, and thinks "Aha! This is the start of a
conversion specifier!" It then tries to figure out what to
do with the conversion specifier "% ", and gets confused
because there is no percent-space specifier. What happens
next is anybody's guess: You've given printf() an invalid
format, and printf() can do whatever it feels like.

Suggestion: Change the final printf() to

fputs (szBuffer, stdout);

.... which just writes the characters of szBuffer without
trying to interpret them as a format string. (In the example
code, szBuffer isn't really necessary: You could just use
vprintf(), or discard myPrintf() altogether and use printf().
But I assume this is a stripped-down example, and that you
intend to do more with szBuffer than you've shown here.)
 
S

Seebs

First, how to count arguments passed ?

You can't. You have to have some other source of information to tell
you what arguments were passed.
I see that va_arg macro can be used, but if don't know type of
arguments ?

Then you're screwed. That's why printf needs a format string.
Then, How can a print a % sign with vsnprintf ?
%%.

void myPrintf(char *szText, ...)
{
char szBuffer[BUFFER_SIZE] = { 0 };
va_list pArgList = NULL;

va_start(pArgList, szText);
vsnprintf(szBuffer, BUFFER_SIZE, szText, pArgList);
va_end(pArgList);

printf(szBuffer);

Hah.

What is in szBuffer?

"this string should show a % (percent sign)\n"

What happens when you pass this string, containing only a SINGLE
percent sign, to printf?

Maybe you should use another function in order to display your
output, such as fwrite. Or, if you want to be silly but not do
something partiicularly dangerous:
printf("%s", szBuffer);

The camel-case and type prefixes are unidiomatic and not useful; if
you're going to write C, I recommend you avoid them.

-s
 
A

Alessio

Eric Sosman ha scritto:
... which just writes the characters of szBuffer without
trying to interpret them as a format string. (In the example
code, szBuffer isn't really necessary: You could just use
vprintf(), or discard myPrintf() altogether and use printf().
But I assume this is a stripped-down example, and that you
intend to do more with szBuffer than you've shown here.)

Yes, is a part of a log function.

Thank you, very useful answers,
Alessio
 
A

Alessio

Seebs ha scritto:
The camel-case and type prefixes are unidiomatic and not useful; if
you're going to write C, I recommend you avoid them.

I don't want to make a flame, but I think that "The camel-case and type
prefixes are unidiomatic and not useful" for you.
Why you recommend to avoid them ?

Alessio.
 
S

Seebs

Seebs ha scritto:
I don't want to make a flame, but I think that "The camel-case and type
prefixes are unidiomatic and not useful" for you.

"Idiomatic" in this case refers to the broader category of C programming.
Why you recommend to avoid them ?

Long story.

Idiomatic usage is an important thing, because people have to work on other
peoples' code. It is easier for everyone to write correct and efficient C
if people follow common conventions. The bulk of existing C has standardized
on names like do_some_things() rather than doSomeThings(). That means that,
in a large project, there will always be a fair amount of code which has
to refer to functions which have lowercase-and-underscores names. If you use
camel case for your new functions, you've created a barrier to quick and
effective programming; someone who remembers the words "do some things"
has to *remember* which way you spelled them, rather than simply writing them
using the standard convention. This is of course caught mostly at compile
time, but it's a hassle and a distraction.

Type prefixes are in general stupid in a strongly-typed language. They
distract the reader from the variable's function to interject with information
the reader probably already has readily at hand.

adverbBasically, conjunctionIf nounYou verbFind pronounThis adjectiveReadable,
conjunctionMaybe pronounIt verbWorks prepositionFor pronounYou. For most
people, it doesn't work.

-s
 
A

Alessio

Seebs ha scritto:
Idiomatic usage is an important thing, because people have to work on other
peoples' code. It is easier for everyone to write correct and efficient C
if people follow common conventions. The bulk of existing C has standardized
on names like do_some_things() rather than doSomeThings(). That means that,
in a large project, there will always be a fair amount of code which has
to refer to functions which have lowercase-and-underscores names. If you use
camel case for your new functions, you've created a barrier to quick and
effective programming; someone who remembers the words "do some things"
has to *remember* which way you spelled them, rather than simply writing them
using the standard convention. This is of course caught mostly at compile
time, but it's a hassle and a distraction.

Type prefixes are in general stupid in a strongly-typed language. They
distract the reader from the variable's function to interject with information
the reader probably already has readily at hand.

adverbBasically, conjunctionIf nounYou verbFind pronounThis adjectiveReadable,
conjunctionMaybe pronounIt verbWorks prepositionFor pronounYou. For most
people, it doesn't work.

-s

Good hints, thanks.

Alessio.
 
N

Nick Keighley

this is of course Mr.Seebach's opionion. It may be better than most
opinions on C but it is still an opinion. I can live with camel case.
Actually I have to, as source bases I deal with in both C and C++ are
CamelCased. For reasons I'm not too sure about camelCase seems much
more prevelent in the C++ than the C world. You can reprogram yourself
to be equally happy in either.

Type prefixs on the other hand are Pure Evil. Search for Hungarian
Notation on the internet.

unless the rest of project team is using them. Or you're using an API
that uses them heavily (eg. Win32). I tend to hide Win32's programming
conventions away from the rest of my code as much as possible. And
only partly becasue they're ugly?
"Idiomatic" in this case refers to the broader category of C programming.

do you have figures?

Long story.

Idiomatic usage is an important thing, because people have to work on other
peoples' code.  It is easier for everyone to write correct and efficient C
if people follow common conventions.  The bulk of existing C has standardized
on names like do_some_things() rather than doSomeThings().

I've seen a fair amount that doesn't follow your conventions!

 That means that,
in a large project, there will always be a fair amount of code which has
to refer to functions which have lowercase-and-underscores names.  

not always...

If you use
camel case for your new functions, you've created a barrier to quick and
effective programming; someone who remembers the words "do some things"
has to *remember* which way you spelled them, rather than simply writing them
using the standard convention.  This is of course caught mostly at compile
time, but it's a hassle and a distraction.

Type prefixes are in general stupid in a strongly-typed language.  

oh agreed. stupid-stupid-stupid might be nearer the mark

They
distract the reader from the variable's function to interject with information
the reader probably already has readily at hand.

He should if he writes decent code. The variable you need to know the
type of should be either local or a parameter (and hence local again)
about 95% of the time. Which means it should only be about 20 lines
away at most (you do write functions that fit on a screen, yes?). Ok,
you may have some static stuff at the head of the file, but *that*
isn't far away either.

I know structs mess up this idealised world, but good naming naming
conventions and modularisation practices clean this all up. And you do
have a decent sourec code browser don't you?
adverbBasically, conjunctionIf nounYou verbFind pronounThis adjectiveReadable,
conjunctionMaybe pronounIt verbWorks prepositionFor pronounYou.  For most
people, it doesn't work.


Consider this URL that discusses a common Hungarian Type in
Microsoft's Windows API
blogs.msdn.com/oldnewthing/archive/2003/11/25/55850.aspx

****************
What do the letters W and L stand for in WPARAM and LPARAM?
Once upon a time, Windows was 16-bit. Each message could carry with it
two pieces of data, called WPARAM and LPARAM. The first one was a 16-
bit value ("word"), so it was called W. The second one was a 32-bit
value ("long"), so it was called L.

You used the W parameter to pass things like handles and integers. You
used the L parameter to pass pointers.

When Windows was converted to 32-bit, the WPARAM parameter grew to a
32-bit value as well. So even though the "W" stands for "word", it
isn't a word any more. (And in 64-bit Windows, both parameters are 64-
bit values!)

It is helpful to understand the origin of the terms. If you look at
the design of window messages, you will see that if the message takes
a pointer, the pointer is usually passed in the LPARAM, whereas if the
message takes a handle or an integer, then it is passed in the WPARAM.
(And if a message takes both, the integer goes in the WPARAM and the
pointer goes in the LPARAM.)

Once you learn this, it makes remembering the parameters for window
messages a little easier. Conversely, if a message breaks this rule,
then it sort of makes your brain say, "No, that's not right."
*******************

In other words the Hungarian doesn't mean what it says it means.
 
S

Seebs

this is of course Mr.Seebach's opionion. It may be better than most
opinions on C but it is still an opinion. I can live with camel case.
Actually I have to, as source bases I deal with in both C and C++ are
CamelCased. For reasons I'm not too sure about camelCase seems much
more prevelent in the C++ than the C world. You can reprogram yourself
to be equally happy in either.

Probably. I'm not convinced that you can actually ever make camelcase
as fast as words separated by visual space, but it can certainly be
livable. I use it in Java, and use it partially in Ruby (where conventions
are a bit more complex; generally, class names are CamelCase, methods
aren't).
Type prefixs on the other hand are Pure Evil. Search for Hungarian
Notation on the internet.

To be fair, there's some case to be made for apps hungarian, which actually
CAN make it easier to spot bugs that a compiler can't.
unless the rest of project team is using them. Or you're using an API
that uses them heavily (eg. Win32). I tend to hide Win32's programming
conventions away from the rest of my code as much as possible. And
only partly becasue they're ugly?

Heh.

But yeah, you make good points -- it can be more important to do things
aligned with the rest of the code base.
do you have figures?

Not really.
I've seen a fair amount that doesn't follow your conventions!

Oh, sure. But look at all the naming conventions used in, say, the C
standard, the standard library implementations, the kernels...
not always...

I've yet to see a decently-written C project not use the standard library
(unless it was freestanding, and all the kernel code I've seen sticks
with lowercase/underscores).
In other words the Hungarian doesn't mean what it says it means.

Yes.

Had they used names like "value" and "pointer", there would be no confusion
and no need for that explanation.

-s
 
N

Nick Keighley

[...] I can live with camel case. [...] You can reprogram yourself
to be equally happy in either [camel or non-camel].

Probably.  I'm not convinced that you can actually ever make camelcase
as fast as words separated by visual space,

to read or to write?

[...]
To be fair, there's some case to be made for apps hungarian, which actually
CAN make it easier to spot bugs that a compiler can't.

and I use postfixes in C++ for the n-zillion different type of smart
pointer.

autoptr<Thing> thingAP;
sharedptr<Thing> thingSP;
dumbptr<Thing> thingDp;

but that may reflect on my ability to deal with C++s smart pointers.
{for the non-C++ those pointers probably all do different things to
the object they point at when they go out of scope)
Heh.

But yeah, you make good points -- it can be more important to do things
aligned with the rest of the code base.



Not really.

people don't usually so its kind of mean to ask.
:)

Oh, sure.  But look at all the naming conventions used in, say, the C
standard, the standard library implementations, the kernels...

well if you must confine yourself to such a narrow domain.

I've yet to see a decently-written C project not use the standard library
(unless it was freestanding, and all the kernel code I've seen sticks
with lowercase/underscores).

I was going to argue a great deal of the code doesn't acll the
standard library. But once strcpy() aand so on considered you probably
can't go many pages without hitting something standard. I don't
actually like camel case I just have to use it.

Yes.

Had they used names like "value" and "pointer", there would be no confusion
and no need for that explanation.

It's my favourite example!
 
P

Phil Carmody

Seebs said:
"Idiomatic" in this case refers to the broader category of C programming.


Long story.

Idiomatic usage is an important thing, because people have to work on other
peoples' code. It is easier for everyone to write correct and efficient C
if people follow common conventions. The bulk of existing C has standardized
on names like do_some_things() rather than doSomeThings(). That means that,
in a large project, there will always be a fair amount of code which has
to refer to functions which have lowercase-and-underscores names. If you use
camel case for your new functions, you've created a barrier to quick and
effective programming; someone who remembers the words "do some things"
has to *remember* which way you spelled them, rather than simply writing them
using the standard convention. This is of course caught mostly at compile
time, but it's a hassle and a distraction.

Type prefixes are in general stupid in a strongly-typed language.

Erm, no need to head off-topic - you're posting to comp.lang.c,
remember?!
They
distract the reader from the variable's function to interject with information
the reader probably already has readily at hand.

So we ought to strip the annoying 'f' from open(), write(), flush(), and
printf()? And as for those new-fangled 'mb' & 'wc' functions - be gone!

Great. Now we need a new language, you just broke the old one ;-p

Phil
 
S

Seebs

So we ought to strip the annoying 'f' from open(), write(), flush(), and
printf()?

I'd say probably not. Prefixes on functions to tell you what they operate
on make some sense, because the function is not declared right here.
Prefixes on variables declared within a function or in its parameter
list are sort of pointless, because the variable is right there to look at.

Thus, "strchr()" not "chr()" (after all, what if you wanted to find a
character in something other than a string?), but "s", not
"strArgumentString1".

-s
 
K

Keith Thompson

Phil Carmody said:
So we ought to strip the annoying 'f' from open(), write(), flush(), and
printf()? And as for those new-fangled 'mb' & 'wc' functions - be gone!

Great. Now we need a new language, you just broke the old one ;-p

The C standard library is not, never has been, and almost certainly
never will be a model of internal consistency.

Apart from Seebs's remarks about the distinction between functions
and (local) variables, functions need to have distinct names, and
there are often multiple versions of a given function that operate
on different types. The 'f' on sqrtf() is more for the compiler's
(and linker's) benefit than for the reader's benefit.

(Yes, I'm responding seriously to what was probably at least partly
written in jest, but there are serious points to be made.)
 
P

Phil Carmody

Keith Thompson said:
The C standard library is not, never has been, and almost certainly
never will be a model of internal consistency.

Apart from Seebs's remarks about the distinction between functions
and (local) variables, functions need to have distinct names, and
there are often multiple versions of a given function that operate
on different types. The 'f' on sqrtf() is more for the compiler's
(and linker's) benefit than for the reader's benefit.

(Yes, I'm responding seriously to what was probably at least partly
written in jest, but there are serious points to be made.)

Indeed. I don't stick my tongue out to Peter unless I'm joshing.

The switching of functions for variables was indeed not very subtle
sleight of hand too, but as I'd just seen "do_some_things() rather
than doSomeThings()", I thought I could conflate the two objections.

And I would have got away with it if it wasn't for you pesky meddling
regs ;-p

Phil
 
N

Nick Keighley

so Algol-60 had it right after all!

integer size buffer;
variable argument start (arg list, size text);


"ALGOL 60 was a language so far ahead of its time that it
was not only an improvement on its predecessors but also
on nearly all its successors".
--C.A.R. Hoare

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,120
Latest member
ShelaWalli
Top