D.A.: On Wed, 6 Feb 2002, Henrik Stuart wrote: > However, the benefit of cout over the printf-family is... type > safety and overloading. :o) > > Consider this: > > short s = 37; > int n = 38; > fprintf(fp, "%d %d", s, n); // fp being a FILE* > fout << s << ' ' << n; // fout being a std::ofstream 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. > However, the iostream capabilities do not come to their full right > until we look at an example where we want the representation of > something when written to always be the same - an obvious choice to > look at as an example would be outputting a matrix: > > std::ostream& operator<<(std::ostream& os, const Matrix& m) { > for (int i = 0; i < m.rows(); ++i) { > for (int j = 0; j < m.cols(); ++j) { > os << m.at(i,j) << ", "; > } > os << std::endl; > } > os << std::endl; > return os; > } Cheesy example follows: char *sprintmatrix(const matrix *m, const char *format) { char *ret; int total = 0, pos = 0; int i, j; for (i = 0; i < m->rows; i++) { for (j = 0; j < m->cols; j++) { total += snprintf(NULL, 0, format, m->a[i][j]); total += 2; /* ", " */ } total++; /* \n */ } total++; /* \n */ ret = malloc(total + 1); for (i = 0; i < m->rows; i++) { for (j = 0; j < m->cols; j++) { pos += snprintf(ret + pos, total - pos, format, m->a[i][j]); pos += strlcpy(ret + pos, ", ", 2); } ret[pos++] = '\n'; } ret[pos++] = '\n'; return ret; } 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. 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. 3) This isn't an example of what is good, just that it can be done. 4) It's not checking for errors from snprintf() due to MailerCode(tm). 5) You could just use something like GLIB's: /* calculate a string size, guarranteed to fit format + args. */ guint g_printf_string_upper_bound (const gchar* format, va_list args); or its: gchar* g_strdup_printf (const gchar *format, ...) G_GNUC_PRINTF (1, 2); 6) You'd probably make 'format' part of 'matrix *' if you did it a lot. > Normally, with a few changes, we would reproduce the double > for-loop every time we want to print a matrix (the apt pupil would > most likely wrap this in a few functions) - however, the force in > the iostream library lies in the inheritance, so with just the > above code we can do all of this: > > Matrix m<4,4>; // creates a 4x4 matrix > std::cout << m; > std::ofstream fout("outfile.txt"); > fout << m; > fout.close(); 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. 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. -- George Greer greerga@circlemud.org -- +---------------------------------------------------------------+ | 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