--------------------------------------------------------------------------------
Hi,
I was wondering if we can create a va_list by adding objects in the
va_list instead of passing in the parameter preceding first optional
argument? In another words, I want to create a va_list in a similar
manner as creating an array.
The reason is I want to use FormatMessage() in my program where it
takes in a va_list as an argument, but the objects that I would like
to pass in with the va_list is not in the form of a parameter
argument.
I tried doing the following but obviously it won't work, but I have no
idea:
va_list temp;
va_arg(temp, long) = value1;
va_arg(temp, long) = value2;
ANy help would be greatly appreciated,
Thanks,
Peter
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kspoon
|
2/15/2005 10:48:11 PM |
|
"Peter" <kspoon@gmail.com> wrote >
> The reason is I want to use FormatMessage() in my program where it
> takes in a va_list as an argument, but the objects that I would like
> to pass in with the va_list is not in the form of a parameter
> argument.
>
> I tried doing the following but obviously it won't work, but I have no
> idea:
>
> va_list temp;
> va_arg(temp, long) = value1;
> va_arg(temp, long) = value2;
You can technically only create a va_list within a variadic function using
the "..." arguments using the macros made for doing such a thing. va_list
and any function that uses va_list is not C++, it's C. If you insist on
using
va_list post this question on comp.lang.c.
Since we're in the C++ forum, maybe you know of some alternatives to
C-style variadic functions. A std::vector<boost::any> seems like a great
fit for your problem.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Mike
|
2/17/2005 9:34:25 AM
|
|
Mike Jolley wrote:
> "Peter" <kspoon@gmail.com> wrote >
>> The reason is I want to use FormatMessage() in my program where it
>> takes in a va_list as an argument, but the objects that I would like
>> to pass in with the va_list is not in the form of a parameter
>> argument.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/formatmessage.asp
the description of the last argument to FormatMessage contains explanation
of what to do in OP case.
> va_list and any function that uses va_list is not C++, it's
> C. If you insist on using
> va_list post this question on comp.lang.c.
That's news for me. What language does std::printf belong to?
--
Eugene
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/18/2005 2:58:59 AM
|
|
>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/formatmessage.asp
>
>the description of the last argument to FormatMessage contains explanation
>of what to do in OP case.
Oh, this is some kind of an MFC thing, no wonder.
>> va_list and any function that uses va_list is not C++, it's
>> C. If you insist on using
>> va_list post this question on comp.lang.c.
>
> That's news for me. What language does std::printf belong to?
It belongs to the ugly part of C++ needed to compile old C code.
Yes, it's officially C++, but only for the sake of backward compatability.
Technically, varargs is an option when you really need an unlimited
number of arguments of varying types, but C++ stream I/O is
an example of how to get around that apparent necessity
without losing type safety.
Sorry Peter, I didn't know what you were dealing with. I
shouldn't have made a statement that wasn't strictly correct,
but then again, I'm not sorry to say that C-style variadic
functions are outdated and incompatible with the desire
for type safety. And MFC sucks.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Mike
|
2/18/2005 11:08:01 AM
|
|
Mike Jolley wrote:
> If you insist on using va_list post this question on
> comp.lang.c.
That's news to me. Post a question about <cstdarg> in
comp.lang.c, and see what they have to say about it. (Of
course, if this statement were in any way true, the moderators
would have rejected the original posting as being off topic.)
> Since we're in the C++ forum, maybe you know of some
> alternatives to C-style variadic functions. A
> std::vector<boost::any> seems like a great fit for your
> problem.
That C++ has other, more effective tools, that can be used in
many cases is a different argument. (Note that there have been
any number of implementations of printf functionality in C++.
At least Samuel Krempp and I (and doubtlessly many others) have
managed to do it without <cstdarg>. Nor anything like
boost::any.)
--
James Kanze GABI Software
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kanze
|
2/19/2005 5:55:39 AM
|
|
Mike Jolley wrote:
>> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/formatmessage.asp
>>
>> the description of the last argument to FormatMessage contains
>> explanation
>> of what to do in OP case.
>
> Oh, this is some kind of an MFC thing, no wonder.
No this has nothing to do with MFC. Just a plain OS API that tries to be
friendly to callers from _all_ languages. You may want to look closely at
how they managed it.
>>> va_list and any function that uses va_list is not C++, it's
>>> C. If you insist on using
>>> va_list post this question on comp.lang.c.
>>
>> That's news for me. What language does std::printf belong to?
>
> It belongs to the ugly part of C++ needed to compile old C code.
Ugliness is in the eyes of the beholder. I actually see stdio including
printf as one of the nicest parts of C++.
> Yes, it's officially C++, but only for the sake of backward
> compatability.
Could you point a clause in standard that says so? Or at least to a place
where significant part of standard committee members express such opinion.
Otherwise it is just speculation.
> Technically, varargs is an option when you really need an unlimited
> number of arguments of varying types, but C++ stream I/O is
> an example of how to get around that apparent necessity
> without losing type safety.
And with loosing many other things including code clarity, separation of
formating and data and (practically) speed. Gosh even the latest Java
re-introduced printf because various OO alternatives aren't as usable.
> I'm not sorry to say that C-style variadic
> functions are outdated and incompatible with the desire
> for type safety.
But they may be *made* type-safe. See the recent thread on fixing printf for
example or languages such as Java or C# that do have type safe variadic
functions.
> And MFC sucks.
Yes it does but not because of variadic functions ;-)
--
Eugene
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/19/2005 3:32:32 PM
|
|
Ok, from now on I'll think of this forum as dealing with standard C++ and
not best practices and such. I'm kind of wrong when I say something is not
C++ when it actually is in the standard. The next time I want to say
something is not C++, I'll just say there are better techniques available or
something, but I still feel that some parts of C++ just aren't in the spirit
of C++ and are only there for backward compatability. Yes, this
compatability is a feature of C++, but should people write new code using
stuff like varargs when it's known to be problematic at best?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Mike
|
2/19/2005 3:40:44 PM
|
|
kspoon@gmail.com (Peter) wrote (abridged):
> I was wondering if we can create a va_list by adding objects in the
> va_list instead of passing in the parameter preceding first optional
> argument? In another words, I want to create a va_list in a similar
> manner as creating an array.
I think the only portable way is to have an intermediate function that
unpacks the array into function arguments.
void to_va( const char *fmt, const long array[2] ) {
to_va( fmt, array[0], array[1] );
}
void to_va( const char *fmt, long value0, long value1 ) {
va_list list;
va_start( list, fmt );
vprintf( fmt, list ); // Or whatever you want to call.
va_end( list );
}
Generalising this to handle arbitrary types and array sizes I leave as an
exercise for the reader.
-- Dave Harris, Nottingham, UK
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
brangdon
|
2/19/2005 3:45:57 PM
|
|
Mike Jolley wrote:
> Ok, from now on I'll think of this forum as dealing with
> standard C++ and not best practices and such.
It's both. Which does mean that you occasionnally have to be
clear which one you mean.
The forum is also not only concerned with standard C++, but with
generally portable C++ -- there too, you have to make a
distinction, and you'll rarely see a posting about export
without a mention that there's a good chance your compiler
doesn't support it next.
> I'm kind of wrong when I say something is not C++ when it
> actually is in the standard.
You're totally wrong. There's a big difference between: "it's
not C++", and "it's not good C++", or "it's not idiomatic C++".
Regretfully, sorta, but that's the way it is.
> The next time I want to say something is not C++, I'll just
> say there are better techniques available or something, but I
> still feel that some parts of C++ just aren't in the spirit of
> C++ and are only there for backward compatability.
I'm pretty sure your right. Still, for whatever reasons, printf
seems to continue to be used. I'll admit that I find it hard to
understand, too. I don't think I've ever seen a C++ application
without at least one overload of operator<< or >>. And
practically all of mine have a few user defined streambuf as
well. Functionality that simply isn't available in printf.
On the other hand, most of my programs require multi-lingual
messages, with positional parameters. And with only one
exception, all of my work has been on Open Group systems. So
the Open Group extensions to printf have been mighty tempting;
in fact, my initial implementation of GB_Format was just to
prove to a customer that we could do the same thing in "real"
C++.
> Yes, this compatability is a feature of C++, but should people
> write new code using stuff like varargs when it's known to be
> problematic at best?
Well, I've not used varargs once in C++. (Except when calling
one of the exec functions.) There's always been a better
solution.
--
James Kanze home: www.gabi-soft.fr
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
James
|
2/20/2005 4:40:04 AM
|
|
James Kanze wrote:
> Still, for whatever reasons, printf
> seems to continue to be used. I'll admit that I find it hard to
> understand, too. I don't think I've ever seen a C++ application
> without at least one overload of operator<< or >>. And
> practically all of mine have a few user defined streambuf as
> well. Functionality that simply isn't available in printf.
[...]
> On the other hand, most of my programs require multi-lingual
> messages, with positional parameters.
Take a look at the FormatMessage function that started this thread[1]. It is
a workhorse routine for localization of messages on Win32 that combines
'positional' sprintf with message catalog access. It is probably possible to
somehow implement equivalent functionality in iostream-friendly way but I
don't see any need for it. A simple RAII wrapper that understands
std::[w]strings is more than enough for my needs. Honestly the whole
"varargs are unsafe" argument is blown out of all proportions. I had met a
few errors in this area but they are even more rare than if (a=b) bugs. If
the committee really is concerned about varargs safety a good solution would
be typesafe varargs similar to Java and C#.
As for extensibility and operator<< this just doesn't work for me. Usually
there is no single good way to output a complicated object so either I
should spend my time inventing manipulators and digging in details of
iword/pword stuff or I could just have special functions that output an
object in a particular way. Which means that _all_ I need from iostreams is
to be able to output built-ins. And sprintf does it in much simpler way. How
do you do "%08X" in iostreams? ;-)
Then there is compactness problem. There is something inherently wrong in
writing 5 lines of code when you can write one.
Finaly there are lots of QoI issues with iostream implementations (and this
is what 2005?). Take fstream for example. On my platform opening a file with
wchar_t * name is a well defined operation and yet my standard library
doesn't provide such an extension. Often I need to perform output on a file
open by some OS API in a certain non-portable way but my library doesn't
provide fstream constructor which takes a file descriptor. Surely I can
write my own streambuf but why should I waste my time doing that when _the
same exact library_ does allow me to create a FILE * from an OS handle?
At the end it all boils down to development time. Probably all iostream
problems may be solved with sufficient time and resources devoted to it. But
none of the projects I ever worked on had time to spend on such activities.
--
Eugene
[1] -
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/formatmessage.asp
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/20/2005 5:21:43 PM
|
|
Eugene Gershnik wrote:
> Honestly the whole
> "varargs are unsafe" argument is blown out of all proportions. I had met a
> few errors in this area but they are even more rare than if (a=b) bugs. If
> the committee really is concerned about varargs safety a good solution would
> be typesafe varargs similar to Java and C#.
How do you rewrite
template<typename T> void foo(T t)
{
// ...
std::cout << t << '\n';
}
using printf() ?
Or how to portably print a value of the type std::size_t? Well,
printf("%lu\n", static_cast<unsigned long>(sizeof(foo)));
should work on all platforms today, but who knows if one day there will be
a platform where std::size_t is something like "unsigned long long"...
This last problem generalises - in quite a lot of code I worked on, the standard
integral or floating point types tended to be "hidden" within typedefs for
portability purposes, but for printing with printf(), you need either to
know the exact underlying type (thus loosing the portability)), or to cast
to a type that is big enough, hoping the cast is value preserving.
printf() is fine in a strongly dynamically typed language like AWK.
> As for extensibility and operator<< this just doesn't work for me. Usually
> there is no single good way to output a complicated object so either I
> should spend my time inventing manipulators and digging in details of
> iword/pword stuff or I could just have special functions that output an
> object in a particular way. Which means that _all_ I need from iostreams is
> to be able to output built-ins. And sprintf does it in much simpler way. How
> do you do "%08X" in iostreams? ;-)
>
> Then there is compactness problem. There is something inherently wrong in
> writing 5 lines of code when you can write one.
No one stops you from writing a manipulator allowing to do the "%08X"
formatting with one line of code and which additionally is typesafe,
unlike printf() where you have to remember when to put "%08X",
"%08lX" or "%08llX" or maybe "%08p" (not sure if the last one is legal).
Falk
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
ISO
|
2/21/2005 8:30:56 PM
|
|
Falk Tannh�user wrote:
> Eugene Gershnik wrote:
>
> How do you rewrite
> template<typename T> void foo(T t)
> {
> // ...
> std::cout << t << '\n';
> }
> using printf() ?
And how do you insert proper manipulators here? A part of my post contains
an explanation why such code is generally useless. The fact that something
*could* be written doesn't mean that people *need* it to be written which
explain why most people are quite happy with printf despite its
shortcomings.
> Or how to portably print a value of the type std::size_t? Well,
> printf("%lu\n", static_cast<unsigned long>(sizeof(foo)));
> should work on all platforms today, but who knows if one day there
> will be
> a platform where std::size_t is something like "unsigned long long"...
Win64 is one such platform. I can use non-standard extension
printf("%Iu\n", sizeof(foo));
UNIX platforms IIRC use
printf("%Zu\n", sizeof(foo));
No doubt any platform that has this issue will take care of it in a similar
manner. So all it takes is a few #defines to generalize it to portable code.
> This last problem generalises - in quite a lot of code I worked on,
> the standard integral or floating point types tended to be "hidden"
> within typedefs for portability purposes, but for printing with
> printf(), you need either to
> know the exact underlying type (thus loosing the portability)), or to
> cast
> to a type that is big enough, hoping the cast is value preserving.
In all code I ever worked on the typedefs where of 2 types
- Ensuring exact size like int32_t
- Providing opaque handle semantics like handle_t
In the first case there are plenty of (non-standard) extensions that allow
output of an integer of a fixed size. In the second case I usually have no
business printing the value or looking at its numerical representation.
Again theoretically we have a problem. Practically it is extremely rare.
>> And sprintf does it in much simpler
>> way. How do you do "%08X" in iostreams? ;-)
>>
>> Then there is compactness problem. There is something inherently
>> wrong in writing 5 lines of code when you can write one.
>
> No one stops you from writing a manipulator allowing to do the "%08X"
> formatting with one line of code
Sure. I just don't have time to perform such exercises.
> and which additionally is typesafe,
> unlike printf() where you have to remember when to put "%08X",
> "%08lX" or "%08llX" or maybe "%08p" (not sure if the last one is
> legal).
Again type-safety is a very marginal issue here.
--
Eugene
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/21/2005 11:33:17 PM
|
|
Eugene Gershnik wrote:
> James Kanze wrote:
> > Still, for whatever reasons, printf seems to continue to be
> > used. I'll admit that I find it hard to understand, too. I
> > don't think I've ever seen a C++ application without at
> > least one overload of operator<< or >>. And practically all
> > of mine have a few user defined streambuf as well.
> > Functionality that simply isn't available in printf.
> [...]
> > On the other hand, most of my programs require multi-lingual
> > messages, with positional parameters.
> Take a look at the FormatMessage function that started this
> thread[1]. It is a workhorse routine for localization of
> messages on Win32 that combines 'positional' sprintf with
> message catalog access.
I'm not too sure that it's a good idea to combine them.
> It is probably possible to somehow implement equivalent
> functionality in iostream-friendly way but I don't see any
> need for it.
Leverage off an existing implementation that works? I have no
desire to reimplement formatting doubles if I can avoid it.
> A simple RAII wrapper that understands std::[w]strings is more
> than enough for my needs. Honestly the whole "varargs are
> unsafe" argument is blown out of all proportions. I had met a
> few errors in this area but they are even more rare than if
> (a=b) bugs.
So you don't make mistakes. Other people do.
> If the committee really is concerned about varargs safety a
> good solution would be typesafe varargs similar to Java and
> C#.
The real solution would be to just ban varargs. But there is a
backwards compatibility issue.
> As for extensibility and operator<< this just doesn't work for
> me. Usually there is no single good way to output a
> complicated object so either I should spend my time inventing
> manipulators and digging in details of iword/pword stuff or I
> could just have special functions that output an object in a
> particular way.
My experience has been just the opposite. That in general,
there is only one good way to display a application specific
object -- about all one has to worry about it width().
> Which means that _all_ I need from iostreams is to be able to
> output built-ins. And sprintf does it in much simpler
> way. How do you do "%08X" in iostreams? ;-)
stream << HexFmt( 8 ) << value ;
Note that it also avoids all the problems in sprintf. (I've
never seen portably correct code which used sprintf.)
> Then there is compactness problem. There is something
> inherently wrong in writing 5 lines of code when you can write
> one.
If you want to use sprintf robustly, you'll need a lot more than
five lines. At the very least, you need snprintf.
> Finaly there are lots of QoI issues with iostream
> implementations (and this is what 2005?). Take fstream for
> example. On my platform opening a file with wchar_t * name is
> a well defined operation and yet my standard library doesn't
> provide such an extension.
Should it?
> Often I need to perform output on a file open by some OS API
> in a certain non-portable way but my library doesn't provide
> fstream constructor which takes a file descriptor. Surely I
> can write my own streambuf but why should I waste my time
> doing that when _the same exact library_ does allow me to
> create a FILE * from an OS handle?
> At the end it all boils down to development time. Probably
> all iostream problems may be solved with sufficient time and
> resources devoted to it. But none of the projects I ever
> worked on had time to spend on such activities.
You mean that you've never invested the effort to learn it
correctly. I know the printf family pretty well -- I once
implemented a standard library for C. I've also taken the time
to learn iostream. If I use iostream instead of printf, it's
for the simple reason that it allows me to be more productive.
--
James Kanze GABI Software
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kanze
|
2/22/2005 9:11:02 PM
|
|
kanze@gabi-soft.fr wrote:
> Eugene Gershnik wrote:
>> James Kanze wrote:
>> Honestly the whole "varargs are
>> unsafe" argument is blown out of all proportions. I had met a
>> few errors in this area but they are even more rare than if
>> (a=b) bugs.
>
> So you don't make mistakes. Other people do.
I think you misunderstood my argument. I do make mistakes and other people
make them too. The question is what is the frequency of a particular mistake
not whether it is possible to make it. If we were deprecating things based
on a possibility of mistake we should have banned C++ altogether as well as
all other programming languages.
>> If the committee really is concerned about varargs safety a
>> good solution would be typesafe varargs similar to Java and
>> C#.
>
> The real solution would be to just ban varargs.
Why? What's wrong with typesafe varargs?
>> As for extensibility and operator<< this just doesn't work for
>> me. Usually there is no single good way to output a
>> complicated object so either I should spend my time inventing
>> manipulators and digging in details of iword/pword stuff or I
>> could just have special functions that output an object in a
>> particular way.
>
> My experience has been just the opposite. That in general,
> there is only one good way to display a application specific
> object -- about all one has to worry about it width().
Strange. I usually have at least 2 or 3 (and this is in non GUI code). At
least one for log and another for persistence.
>> How do you do "%08X" in iostreams? ;-)
> stream << HexFmt( 8 ) << value ;
And where can I download HexFmt? ;-)
> Note that it also avoids all the problems in sprintf. (I've
> never seen portably correct code which used sprintf.)
Perhaps. I have never seen really portable code. What I have seen is a code
based on printf that works on all major platforms I care about.
>> Then there is compactness problem. There is something
>> inherently wrong in writing 5 lines of code when you can write
>> one.
>
> If you want to use sprintf robustly, you'll need a lot more than
> five lines. At the very least, you need snprintf.
asprintf(), or _vscprintf() are usually enough. ;-) Most annoying problems
are already taken care of by some non-standard but widely portable means.
>> On my platform opening a file with wchar_t * name is
>> a well defined operation and yet my standard library doesn't
>> provide such an extension.
>
> Should it?
Yes. The same library has _wfopen().
>> At the end it all boils down to development time. Probably
>> all iostream problems may be solved with sufficient time and
>> resources devoted to it. But none of the projects I ever
>> worked on had time to spend on such activities.
>
> You mean that you've never invested the effort to learn it
> correctly. I know the printf family pretty well -- I once
> implemented a standard library for C. I've also taken the time
> to learn iostream. If I use iostream instead of printf, it's
> for the simple reason that it allows me to be more productive.
Perhaps. It could also be that the only way to get productivity out of
iostreams is to have your level of expertise with them. Possibly this is the
answer to your question below
> Still, for whatever reasons, printf
> seems to continue to be used. I'll admit that I find it hard to
> understand, too.
--
Eugene
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/23/2005 12:19:13 AM
|
|
Eugene Gershnik wrote:
> kanze@gabi-soft.fr wrote:
> > Eugene Gershnik wrote:
> >> James Kanze wrote:
> >> Honestly the whole "varargs are unsafe" argument is blown
> >> out of all proportions. I had met a few errors in this
> >> area but they are even more rare than if (a=b) bugs.
> > So you don't make mistakes. Other people do.
> I think you misunderstood my argument. I do make mistakes and
> other people make them too. The question is what is the
> frequency of a particular mistake not whether it is possible
> to make it. If we were deprecating things based on a
> possibility of mistake we should have banned C++ altogether as
> well as all other programming languages.
There are two aspects to consider: frequency and cost. Even if
passing the wrong type is fairly rare, it can be very expensive
to track down and correct.
In my experience, it isn't that rare. It crops up in two
specific cases:
-- A format which is being used several times (say a line in a
table), and in one case, one of the parameters is a
constant, say 0. In this case, I've seen it happen that the
programmer passes a 0 (an int) to a %f (which requires a
float).
-- The translator makes a typo, and accidentally modifies one
of the format specifiers. So the bug only shows up in one
particular language version of the program. (Which means
that you end up having to debug the program with its output
in Finnish, or whatever.)
> >> If the committee really is concerned about varargs safety a
> >> good solution would be typesafe varargs similar to Java and
> >> C#.
> > The real solution would be to just ban varargs.
> Why? What's wrong with typesafe varargs?
OK. The real solution would be to get rid of the current
varargs. I don't feel a great need for varargs in general
(maybe just because I've gotten used to living without them),
but I would certainly have no objections if someone feels they
need a typesafe version.
> >> As for extensibility and operator<< this just doesn't work
> >> for me. Usually there is no single good way to output a
> >> complicated object so either I should spend my time
> >> inventing manipulators and digging in details of
> >> iword/pword stuff or I could just have special functions
> >> that output an object in a particular way.
> > My experience has been just the opposite. That in general,
> > there is only one good way to display a application specific
> > object -- about all one has to worry about it width().
> Strange. I usually have at least 2 or 3 (and this is in non
> GUI code). At least one for log and another for persistence.
Persistence? I've never really been able to make either FILE*
or iostream work for persistence.
> >> How do you do "%08X" in iostreams? ;-)
> > stream << HexFmt( 8 ) << value ;
> And where can I download HexFmt? ;-)
It used to be available at my site. It will again be available
when I get my new site up.
More to the point, I think: generally, you don't want to use low
lever manipulators OR %n.mf. You want to specify high-level
mark-up -- considering your example: LogFmt or PersistFmt. For
specific semantic types, as well; for double, you might have
LogMoney, LogPercent, PersistMoney, PersistPercent, etc. The
point is that if you decide you need one more digit precision in
per cents in your log, you don't have to look through the entire
program to find every place you output a percent to the log.
Which, of course, argues for iostream and its manipulators. It
also argues that any good format class will support
manipulators, as a means of separating the formatting
information from the text.
But I'll admit that I don't think that this practice is very
wide spread. (I only adopted it myself within the last year.)
> > Note that it also avoids all the problems in sprintf. (I've
> > never seen portably correct code which used sprintf.)
> Perhaps. I have never seen really portable code. What I have
> seen is a code based on printf that works on all major
> platforms I care about.
printf works, although it is fragile. sprintf is broken, to an
extent that the C standards committee felt the need to provide a
replacement (snprintf).
> >> Then there is compactness problem. There is something
> >> inherently wrong in writing 5 lines of code when you can
> >> write one.
> > If you want to use sprintf robustly, you'll need a lot more
> > than five lines. At the very least, you need snprintf.
> asprintf(), or _vscprintf() are usually enough. ;-) Most
> annoying problems are already taken care of by some
> non-standard but widely portable means.
> >> On my platform opening a file with wchar_t * name is a well
> >> defined operation and yet my standard library doesn't
> >> provide such an extension.
> > Should it?
> Yes. The same library has _wfopen().
The standard is designed for writing portable code. I fully
agree that on a given platform, the vendor should provide
additional, non-standard libraries for features not covered by
the standard. I'd also agree that there are a number of things
which have become widespread enough to be justify standard
support, but which don't have it. Wide character filenames
aren't one of them, however.
> >> At the end it all boils down to development time. Probably
> >> all iostream problems may be solved with sufficient time
> >> and resources devoted to it. But none of the projects I
> >> ever worked on had time to spend on such activities.
> > You mean that you've never invested the effort to learn it
> > correctly. I know the printf family pretty well -- I once
> > implemented a standard library for C. I've also taken the
> > time to learn iostream. If I use iostream instead of
> > printf, it's for the simple reason that it allows me to be
> > more productive.
> Perhaps. It could also be that the only way to get
> productivity out of iostreams is to have your level of
> expertise with them. Possibly this is the answer to your
> question below
> > Still, for whatever reasons, printf seems to continue to be
> > used. I'll admit that I find it hard to understand, too.
Iostreams requires learning a new paradigm. That much is clear.
And it is far from perfect. But then, the same was true for
printf, when I learned C, many years back. Neither are exactly
what I would call comfortable when it comes to complex
formatting. And the syntax of iostream is rebarbative, and the
fact that printf can't be extended for user defined types is
often a killer. Nothing's perfect, but printf's warts have
caused me too much trouble in the past.
--
James Kanze GABI Software
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
kanze
|
2/23/2005 10:37:40 PM
|
|
kanze@gabi-soft.fr wrote:
> Eugene Gershnik wrote:
>> kanze@gabi-soft.fr wrote:
>>> Eugene Gershnik wrote:
>>>> James Kanze wrote:
>
> There are two aspects to consider: frequency and cost. Even if
> passing the wrong type is fairly rare, it can be very expensive
> to track down and correct.
I agree.
> In my experience, it isn't that rare. It crops up in two
> specific cases:
>
> -- A format which is being used several times (say a line in a
> table), and in one case, one of the parameters is a
> constant, say 0. In this case, I've seen it happen that the
> programmer passes a 0 (an int) to a %f (which requires a
> float).
Yes this is the situation I have seen a couple of times.
> -- The translator makes a typo, and accidentally modifies one
> of the format specifiers. So the bug only shows up in one
> particular language version of the program. (Which means
> that you end up having to debug the program with its output
> in Finnish, or whatever.)
Well I had to debug on all far-eastern languages and many european ones,
none of which I understand, and the reasons usually were much more simple
than printf problems (though I have seen them too). Usually people commit
capital sins like reusing a localizable string for non-localizable purposes
or rely on word order in code. Compared to this stuff printf problems are
almost pleasant to deal with.
> Persistence? I've never really been able to make either FILE*
> or iostream work for persistence.
Are we talking about the same concept? What I mean is something like being
able to save an object to file and recreate it later. This is certainly
doable with both FILE * and iostreams. Note that the file doesn't usually
need to be transferrable to a different machine (though sometimes this is
also a requirement).
> More to the point, I think: generally, you don't want to use low
> lever manipulators OR %n.mf. You want to specify high-level
> mark-up -- considering your example: LogFmt or PersistFmt. For
> specific semantic types, as well; for double, you might have
> LogMoney, LogPercent, PersistMoney, PersistPercent, etc. The
> point is that if you decide you need one more digit precision in
> per cents in your log, you don't have to look through the entire
> program to find every place you output a percent to the log.
But isn't that what OO is all about? If I output a particular kind of
information most likely it will be from the same class. IOW if I ouput money
I will have Money class not a plain double. If I decide to change digit
precision then I will need to modify only a class or two.
> Which, of course, argues for iostream and its manipulators. It
> also argues that any good format class will support
> manipulators, as a means of separating the formatting
> information from the text.
Formating - yes, content - no. If I have a class that contains a vector
holding 1 meg of data I don't want to print this vector into the log but I
certainly need to do so for persistence. The only one qualified to decide is
the class itself since nobody else even knows about the vector. Using
manipulators is certainly possible but one will have to devise some kind of
interaction between manipulator and class being written.
>>>> On my platform opening a file with wchar_t * name is a well
>>>> defined operation and yet my standard library doesn't
>>>> provide such an extension.
>
>>> Should it?
>
>> Yes. The same library has _wfopen().
>
> The standard is designed for writing portable code. I fully
> agree that on a given platform, the vendor should provide
> additional, non-standard libraries for features not covered by
> the standard. I'd also agree that there are a number of things
> which have become widespread enough to be justify standard
> support, but which don't have it. Wide character filenames
> aren't one of them, however.
Sure. This part of my initial post was about library QoI not standard.
Iostreams in some form have been around for a long time and we still cannot
do frequently needed things easily on every platform.
> Iostreams requires learning a new paradigm. That much is clear.
> And it is far from perfect. But then, the same was true for
> printf, when I learned C, many years back. Neither are exactly
> what I would call comfortable when it comes to complex
> formatting. And the syntax of iostream is rebarbative, and the
> fact that printf can't be extended for user defined types is
> often a killer. Nothing's perfect, but printf's warts have
> caused me too much trouble in the past.
I think we mainly agree about the facts but differ in our reaction to them.
Printf shortcomings are below mine irritability threshold and above yours.
--
Eugene
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/24/2005 9:48:25 PM
|
|
"Eugene Gershnik" <gershnik@hotmail.com> wrote in message
news:Y7qdnfakoOPOnIPfRVn-hQ@speakeasy.net...
> kanze@gabi-soft.fr wrote:
>> Eugene Gershnik wrote:
>>> kanze@gabi-soft.fr wrote:
>>>> Eugene Gershnik wrote:
>>>>> James Kanze wrote:
>>
>> There are two aspects to consider: frequency and cost. Even if
>> passing the wrong type is fairly rare, it can be very expensive
>> to track down and correct.
>
> I agree.
>
>> In my experience, it isn't that rare. It crops up in two
>> specific cases:
>>
>> -- A format which is being used several times (say a line in a
>> table), and in one case, one of the parameters is a
>> constant, say 0. In this case, I've seen it happen that the
>> programmer passes a 0 (an int) to a %f (which requires a
>> float).
etc. etc.
This whole thing is a discussion of the balance between safety and ease of
implementation. I saw Scott Meyers talk about type safety, and he described
a way to make a Month class that can take on 12 distinct values and no
others. It has assignment operators and copy constructors that enforce the
rules of what it means for something to be a Month. The whole time he was
saying that this is just a simple example of using the compiler's type
safety mechanisms to bullet-proof your code. After he was done talking,
nobody got the idea. They just said, "Why not just use an enum?"
I've wasted years just getting job after job done in a lame way. From now
on, I want my code to be bullet-proof.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Mike
|
2/27/2005 11:43:38 AM
|
|
Eugene Gershnik wrote:
> kanze@gabi-soft.fr wrote:
>>Eugene Gershnik wrote:
>>>kanze@gabi-soft.fr wrote:
>>>>Eugene Gershnik wrote:
>>>>>James Kanze wrote:
[...]
>>Persistence? I've never really been able to make either FILE*
>>or iostream work for persistence.
> Are we talking about the same concept?
Maybe not.
> What I mean is something like being able to save an object to
> file and recreate it later. This is certainly doable with
> both FILE * and iostreams. Note that the file doesn't usually
> need to be transferrable to a different machine (though
> sometimes this is also a requirement).
Most of my work has been on large scale, critical servers.
Persistence means that if the program or the machine crashes,
when it restarts, it recovers to the state of the last committed
operation -- the last operation for which it has sent an
acknowledge, if you prefer. Neither FILE* nor iostreams are of
much use here.
It does occur to me that a lot of GUI programs allow you to
modify the configuration (colors, etc.) interactively, although
they store the data in a configuration file with a standard
format. I guess that this is persistence as well, and for this,
I think that either FILE* or iostream would do the job quite
well.
>>More to the point, I think: generally, you don't want to use
>>low lever manipulators OR %n.mf. You want to specify
>>high-level mark-up -- considering your example: LogFmt or
>>PersistFmt. For specific semantic types, as well; for double,
>>you might have LogMoney, LogPercent, PersistMoney,
>>PersistPercent, etc. The point is that if you decide you need
>>one more digit precision in per cents in your log, you don't
>>have to look through the entire program to find every place
>>you output a percent to the log.
> But isn't that what OO is all about? If I output a particular
> kind of information most likely it will be from the same
> class. IOW if I ouput money I will have Money class not a
> plain double. If I decide to change digit precision then I
> will need to modify only a class or two.
Sort of. I'll admit that I more or less thought of it a lot
like that for a long time. On my last contract, however, a
collegue asked me the question whether it made sense for a class
like Money to know about all the possible output formats. And
the more I thought about it, the more I realized that it
didn't.
In the context of that projecct, we were concerned about various
binary formats: you really don't want to burder your class Money
(or in our case, IPAddress) with the details of BER encoding,
for example. The solution is, I think, some sort of mediator.
(And I'm not sure that money is a good example. In practice,
the class will use width() from the iostreams, but the precision
-- the number of digits after the decimal -- will depend on the
currency, which in turn could depend on many things, but will
often be an internal attribute of the class.)
The point here is, of course, that you don't ever specify n
digits precision when outputting Money or PerCent. You specify
using some sort of semantic mark-up. (If you do advanced text
handling, it's the difference between raw TeX and LaTeX.)
>>Which, of course, argues for iostream and its manipulators.
>>It also argues that any good format class will support
>>manipulators, as a means of separating the formatting
>>information from the text.
> Formating - yes, content - no. If I have a class that contains
> a vector holding 1 meg of data I don't want to print this
> vector into the log but I certainly need to do so for
> persistence. The only one qualified to decide is the class
> itself since nobody else even knows about the vector. Using
> manipulators is certainly possible but one will have to devise
> some kind of interaction between manipulator and class being
> written.
Agreed. I don't have a really good solution -- currently, the
best I can do is that you have several manipulators,
e.g. LogData, PersistenceData, LogWhatever,
PersistenceWhatever. I suppose that when the formats really are
linked to a file, you could use xalloc to save an indicator as
to what type of file it is, and operator<< could automatically
adjust. In this case, the "stickiness" of the attribute is an
advantage. But I'm not totally happy about this either.
Anyway, I don't see any way of making this work with printf.
>>>>>On my platform opening a file with wchar_t * name is a well
>>>>>defined operation and yet my standard library doesn't
>>>>>provide such an extension.
>>>>Should it?
>>>Yes. The same library has _wfopen().
>>The standard is designed for writing portable code. I fully
>>agree that on a given platform, the vendor should provide
>>additional, non-standard libraries for features not covered by
>>the standard. I'd also agree that there are a number of
>>things which have become widespread enough to be justify
>>standard support, but which don't have it. Wide character
>>filenames aren't one of them, however.
> Sure. This part of my initial post was about library QoI not
> standard. Iostreams in some form have been around for a long
> time and we still cannot do frequently needed things easily on
> every platform.
You mean that we are often missing platform specific extensions
which we more or less have the right to expect. I agree there.
My target platforms are mostly Unix -- Posix imposes a certain
number of extensions to FILE*. And nothing for iostreams.
But it's worse. Because more recent versions of the compiler
often remove the extensions which were there before. Don't ask
me why; I can't fathom such regressions, but it's certainly
happened.
>>Iostreams requires learning a new paradigm. That much is
>>clear. And it is far from perfect. But then, the same was
>>true for printf, when I learned C, many years back. Neither
>>are exactly what I would call comfortable when it comes to
>>complex formatting. And the syntax of iostream is
>>rebarbative, and the fact that printf can't be extended for
>>user defined types is often a killer. Nothing's perfect, but
>>printf's warts have caused me too much trouble in the past.
> I think we mainly agree about the facts but differ in our
> reaction to them. Printf shortcomings are below mine
> irritability threshold and above yours.
And vice versa -- iostream's short-comings are below my
irritability threshold, and above yours. That's probably the
explination. It may have to do with the contexts we working in;
depending on what you are trying to do, different problems are
more or less bothersome.
--
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre S�mard, 78210 St.-Cyr-l'�cole, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
James
|
2/28/2005 12:41:14 AM
|
|
Mike Jolley wrote:
> This whole thing is a discussion of the balance between safety and
> ease of implementation.
You probably meant ease of [re-]use. In any case this is not safety vs. ease
but cost vs. benefit.
> I saw Scott Meyers talk about type safety,
> and he described a way to make a Month class that can take on 12
> distinct values and no others. It has assignment operators and
> copy constructors that enforce the rules of what it means for
> something to be a Month. The whole time he was saying that this is
> just a simple example of using the compiler's type safety
> mechanisms to bullet-proof your code. After he was done talking,
> nobody got the idea. They just said, "Why not just use an enum?"
>
> I've wasted years just getting job after job done in a lame way.
> From now on, I want my code to be bullet-proof.
Only if you are an artist. If you are an engineer you probably want your
customers (even if the only customer is yourself) to be happy and your
shareholders (even if your only shareholder is yourself) to spend as little
resources (money, time etc.) as possible. In other words what you really
need is cost/benefit analysis not a blind principle.
To give you an analogy you probably don't live in a bunker and don't drive a
tank. Your house is not bullet-proof and your car can roll over pretty
easily. Yet you buy them because you are not willing to pay more for
reducing risks that you don't consider realistic. And for car manufacturers
trying to make tanks instead of cars would be economic suicide. Of course
there are situations when you really need a tank and only then it makes
sense to build and buy one.
Same holds for software. I haven't been to Scott's classes so I cannot
comment on his presentation style but speaking in general in order to "sell"
something to me you need to prove that I am getting my "money" worth. I can
only assume that his audience saw Month class as a tank and enum as Toyota
Echo ;-) Using Month class instead of enum can only make sense when the
benefits outweght the costs. I personally would ask the following questions
- How much does Month cost to buy: is it bundled with a library I already
use (free), requires to buy a new library, or do I have to write and
maintain it (expensive)
- What is the cost of having a bug fixed in this class?
- How much do we use months in the code? Few times? All over it?
- How many errors in month calculations did we have so far? It is a very old
principle that you should expect more bugs in the area of code where bugs
were already found. If we had month-related problems before chances are we
will have more of them.
At the end I want to decide whether the benefits/cost of using Money is
greater than benefits/cost of using enum. It could be that the answers to
these questions will result in my deciding to use enum instead of the Month
class.
My disagreement with James Kanze is essentially about the same. James (I
think) came to the conclusion that in the area he works the ratio always
favors iostreams. My opinion for the area I work is different.
--
Eugene
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Eugene
|
2/28/2005 1:08:13 AM
|
|
|
18 Replies
124 Views
(page loaded in 0.51 seconds)
|