Greetings, On Thursday, February 07, 2002 4:31:36 AM George Greer wrote: > On Wed, 6 Feb 2002, Henrik Stuart wrote: >> However, the benefit of cout over the printf-family is... type >> safety and overloading. :o) >> > Unless you want to be notified that you're no longer printing an integer > but now a float. Perhaps in 'a == b' cases where comparing a floating > point number is bad? It's all fuzzy and some cases get handled by the > compiler, such as GCC's -Wfloat-equal. Nothing like type-safety in your > *printf functions griping at you (via compiler) for putting the wrong types > in there. The majority of compilers today do not notify of non POD-types[1] being passed to vararg functions (I know gcc does produce a low-level warning on this). Now, consider: const char* abc = "abcdefg"; fprintf(fp, "%s\r\n", abc); then change abc to: const std::string& abc = "abcdefg"; fprintf(fp, "%s\r\n", abc); It's a rather cumbersome process locating these unless you happen to like to use gcc and use -Wall and whatnot. :o) Hence, I prefer just to use iostreams and let the type system handle the rest of the worries - cleaner, less of a headache and less modification when you make a transition from char* to std::string, which is an obvious thing to do with CircleMud. > Cheesy example follows: [snip] I didn't say that it wasn't possible to wrap all of this in a sensible function in C, merely said it wasn't as easy. Now, imho, the sprintmatrix is by far the worse nightmare to maintain over the operator<< version. > Caveats: > 1) I'm not sure "snprintf(NULL, 0, ..." would work. I'd then use a > dummy buffer (as small as 1 byte should work) to get the size. Snprintf returning the needed buffer size is _implementation dependant_ afair. I do not have the most recent version of the C standard close at hand, but I took the time to investigate the working on snprintf of a few of the Windows compilers, and most of them return a negative value if the buffer wasn't large enough - imho that alone should be enough to discourage you to use it in such a fashion (unless, of course it's part of the standard, then it's a shortcoming in the compilers I looked at). Doing proper dynamic memory management in C is a lot more ugly than in an object-oriented language since the ool has data encapsulement as an integral part. > 2) Two passes isn't exactly wonderful. I'd prefer to pass <string,size> > to the function like snprintf does and just punt when running out of > room. Alternatively, you could just worst-case the size and use that. Worst-casing an arbitrary matrix class that could potentially be containing char*'s for automatic symbolic proofs on its' correctness? Now, of course, it's certainly possible if you only have int's in your code. *pats his templates fondly* > 3) This isn't an example of what is good, just that it can be done. It can be done, alright, there's no denying that. :o) You can also write all your code in machine code - that is rarely considered good either these days. :o) > 4) It's not checking for errors from snprintf() due to MailerCode(tm). Errors are strange in the C library - just take atoi for an example... it returns 0 when it fails? Hmm... how do I know I didn't just read a 0? I know that linux contains the errno variable and Windows has the GetLastError(), but afair not a lot of the functions in the standard C library are required to have a specific return code on failure - I might of course be wrong, it has happened before. > 5) You could just use something like GLIB's: Yup, my point wasn't that C++ is _the best_ language - there are things that are more nicely done in other languages, was just giving my point of view on the preference to std::stringstream over *printf. Personally, again, however, I think variable argument lists are ugly and evil, not to mention notoriously error prone. :o) > 6) You'd probably make 'format' part of 'matrix *' if you did it a lot. Yep, but again it's based on variable arguments. One of the beauties with inheritance in C++ is that you can say - when I write to files I want to use a different output format. Then you merely declare the sensible output operator: std::ofstream& operator<<(std::ofstream& ofs, const Matrix& m) { // do some output here in another style } And you would - as "user programmer" not have to concern yourself with reading and/or writing the data, because it's already nicely defined for ASCII files. (That is if you declare a sensible input operator as well for the Matrix classes). > And in my code you just change the "format" parameter to pass "%g" instead > of "%d". As an added bonus, say you wanted brackets around all the > values..."[%d]" is your friend. Or perhaps you want them all 5 digits > wide..."[%5d]", done. Granted this wasn't directly possible in the ultra, ultra short sample I gave in my mail, but it's rather trivial to extend the matrix operator to read the current manipulators and use these sensibly. That is you could make it do something like: std::cout << std::setw(28) << std::left << my_matrix << std::endl; And all the matrix elements would be printed 28 characters wide and left-aligned. Anyway, trivial topic for the interested reader. :o) > NOTE: This doesn't mean I don't want a string library. In fact, I'd really > like to have one. Doesn't the '\0' terminator seem like a crass violation > of data:metadata to you? The string's end is encoded within the string > itself due to the lack of a meta-length field. I just don't see such > things as the silver bullet to bad code. I think the original motivation for using the null terminator rather than a "prefixed" size information (like you have in java) was to avoid using extra memory on that and "the null character is probably not prone to show up in string literals", or something along those lines - I forgot the original reason by K&R. Am not saying that using some sort of metadata is preferable or not, as long as my standard library is "as efficient as possible" and doesn't require me to reinvent the wheel every time I happen to have to use something more complex than the rudimentary functions in the standard C library. Not that it isn't trivial to write linked lists, resizable arrays, sets and whatnot, but it's not trivial to implement them in the "most efficient way" for everyone, let alone force you to do a lot of the work, etc. at many turns. Some of the work could be avoided to have to be done repetitiously in C using some void* stuff (which I really don't like, personally), but merely being able to use the standard template library for sane containers is a comfort that shouldn't be forgotten when picking a programming language at the current date. Granted, one could argue that one should choose Java instead, but I happen to like speed, but that seems to be religious grounds for Java advocates, so I'll rest my case here. :o) [1]: POD-types is primitive old data (ints, chars, shorts, floats, doubles, etc.), basically the non-struct/union stuff in C. It is therefore not possible to stuff a class through a printf statement as it's possible to stuff a class through an operator<<. -- Yours truly, Henrik Stuart (http://www.unprompted.com/hstuart/) -- +---------------------------------------------------------------+ | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html | | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html | | Newbie List: http://groups.yahoo.com/group/circle-newbies/ | +---------------------------------------------------------------+
This archive was generated by hypermail 2b30 : 06/25/03 PDT