Dear Mr. Plauger:I have been reading the C Users Journal since it was little more than a newsletter for the users group. The one thing I have noticed in C programmers is the use of the functions "FOO" and "FOOBAR" within a test module. Where are the origins of such naming conventions, and to what are they attributed? Although, not a technical question, it has aroused my curiosity over the years.
Sincerely,
Mr. Philip Felice
U.S. Trust Company of New York
770 Broadway
New York, NY 10003The terms foo, bar, and foobar all derive from the old U.S. Navy slang FUBAR, their answer to the Army's SNAFU. FUBAR leaked into the programming community through MIT. The (somewhat laundered) Navy term is an acronym for "fouled up beyond all repair," while the Army term is short for "situation normal, all fouled up." pjp
Mr Plauger,
Thank you for doing such a fine job over the years. My first subscription issue came Saturday. Exciting. Exciting an article on neural nets then on page 85 the article falls off the face of the earth????? How beastly clever they have implemented a '50s movie cliff hanger? (OK. OK. Just kidding.)
I'm sure you have really heard about this problem by now. I hope that the end of the article will be in next month's issue. (Well OK, deadlines being what they are the month after?)
This is one issue that I am rushing a check for the source code disk. I really appreciate the cost of the disk to be affordable!
Thanks & Cheers,
deryl
I can't claim credit for that particular gaffe. Some days, there's enough embarrassment to go around. pjp
Diane Thomas, Managing Editor replies:
Profuse apologies for our FUBAR. You can find the correction to that article on page 102 of the October 1992 issue. If you don't care to purchase the October issue, please call or write and I will fax or mail the correction to you.
Editor:
I am constantly impressed with the articles and the quality of The C Users Journal and I want to thank you for all the work that you do. It always disappoints me to read some flame from a reader who is mostly demonstrating his lack of tact or inability to express an opinion without insulting someone. I hope you take all flames with a grain of salt and recognize that most people that are satisfied or happy don't write. I, personally, rarely get the time.
It's also great to see that the Gods and Gurus make mistakes, too. I noticed a goof that you'll probably get a hundred letters on and is one of the ones I've read a number of other gurus do commonly. In your "Bugs" article, your example of violation of coding standards showed the "improved version" as:
char fn[L_tmpnam], *s; if ((str = fopen ((const char *)tmpnam(fn), "wb+")) == NULL) ; else if ((s = (char *)malloc(sizeof (fn) + 1)) == NULL) fclose (str); str = NULL; else str->_Tmpnam = strcpy(s, fn);The erroneous line is the one with the fclose on it. You will notice that there are two statements between the else if and the else with no curly braces. Tsk, tsk, tsk. :-)I've gotten into the habit of always using curly braces just because I made this mistake all the time. Also, I frequently want to put a print statement into the if statement somewhere and then have to put curly braces around it anyway.
Thanks again for all the very interesting articles and wealth of information.
Chris Carlson
carlson@sgi.comHowdy;
I just got the latest issue of The C Users Journal, and was zipping through your "Standard C" column when I noticed that one of your "fixes" contains yet another bug. The offending code appears on page 12. [same code as in previous letter follows pjp] I doubt this will even compile as written.
I'm pretty sure you intended to write:
fclose(str), str = NULL;Don't you just hate when that happens :-)Timothy G. Northrup
...!rutgers!brspyr1!jrsalb1!timYup. Luckily, the error occurred in transcription for publication in the magazine (my fault). The actual code does compile and run its test cases. pjp
Dear Mr. Plauger,
I enjoyed reading your article "Bugs" in the September '92 issue of The C Users Journal. Your book, The Standard C Library is quite informative.
I did notice one example which, as written, has undefined behavior according to The Standard as I understand it. On page 209 your va_fputs function returns without calling va_end on a write error. In your implementation of the library it doesn't make any difference, but as the text points out that may not always be the case.
While I'm on the subject, I don't recall ever reading a discussion of an implementation of the Standard C library suitable for use by multi- threaded programs. I program on the Amiga where spinning off multiple threads is quite easy to do, and while the system shared libraries are written to expect to be called from various tasks at any time, the C linker libraries for the compilers I've looked at expect to have only one caller at a time. Some functions work just fine anyway (strlen for example) while others like strtok (which make use of an internal static variable in the implementations I've seen) are clearly not going to like having multiple asynchronous callers. So if you're looking for an article idea you may want to consider "Library Use by Multiple Concurrent Threads."
Otherwise, it's good to have The Editor reachable via e-mail. Now if we only had a tutorial on the correct spelling of "Plauger." (Wow! Your own domain! Is that anything like the fat jokes, "He's as big as New Jersey" or "He has his own zip code?")
Todd M. Lewis
utoddl@guitar.oit.unc.eduThat's a bug all right. It's already fixed in the second printing, but thanks for reporting it. My brother, Dave Plauger, has just finished making a thread-safe C++ library for Hewlett Packard. I'm trying to coax him into writing an article on what he did. pjp
Dear Mr. Plauger,
This is an answer to Mr. Grabbe's letter in the July issue of CUJ.
The point editor for the PC is available for free using anonymous ftp. Address: unmvax.cs.unm.edu.
login: anonymous password: idIt is located in /pub/Point/ptpc.tar.Z. This is a compressed archive file that will be extracted on (hopefully) any UNIX system using
zcat ptpc.tar.Z | tar xvf -Note: there is also an X-Windows version of point at the same location (best UNIX editor I have ever seen besides emacs/epoch).As far as I know point has been posted to comp.sources.*. Right, Mr. Weinstein? By the way, where is your column? Continue tracking comp.sources.x!
PS: The last issues of CUJ have become somewhat "less academic" maybe due to the discussion some months ago. To me this is a serious drawback for the quality of your magazine.
Yours truly,
Gerhard Wilhelms
Lehrstuhl fuer Informatik I
Universitaet Augsburg
Universitaetsstr. 2
W-8900 Augsburg
GERMANYWhich is a serious drawback, that the magazine is less or more academic? You'd think we could get 50,000 readers to agree on something. Seriously, all we can do is keep striving for a good balance in selecting from submissions. We appreciate your continuing input to help us tune that balance. pjp
Editor:
In the article titled "Bit Arrays with C++" in the July 1992 issue of CUJ, authors A. Giancola and L. Baker chose an approach that seemed very unorthodox to me. If possible I would appreciate a clarification of their design rationale.
The code given in the article cannot, according to the authors themselves, be compiled with a licensed derivative of the AT&T C++ compiler. A second compiler, Borland's C++ v3.0, does compile the code but issues a warning message. The compilation problems stem directly from the use of a nested class inside a template class, a design that Giancola and Baker chose in order to "prevent inadvertent misuse of objects." Why do they consider this possibility to be of such importance? Of what value is "safe" code if it cannot be compiled, or compiles with warnings?
The authors' stated goal was to create a bit array that could be addressed using arithmetic assignment statements of the form A(i,j) = x;. This was quite a difficult problem and required approximately a hundred lines of clever code to solve. An alternate approach would have been to access array elements through an assignment function. this would have required perhaps ten or twenty lines of straightforward code. There is no question that it also would have the advantage of faster execution. To call an access function, one must write a statement of the form A.set(i,j,x); instead of A(i,j) = x;. Is the second form so much cleaner that it is worth the coding effort and the sacrifice in execution speed?
In the first sentence of the article, Giancola and Baker explain that they developed this code while working in a "Go" program. Their task was to represent the Go board, a 19x19 grid in which each location can be either white, black, or empty. This could have been done by using an array of char, e.g., char board[19][19], requiring 361 bytes of storage. No special code would be needed since access to 2-dimensional char arrays is built into the C/C++ language. The implementation chosen by the authors requires only 113 bytes of storage, but at the expense of added complexity.
Unless the program must store a large number of Go positions simultaneously, the modest savings in storage space achieved by the authors hardly seems worth the effort. Furthermore, storing and retrieving values would be relatively efficient for a 19x19 array of characters; packing the information into 113 bytes makes accessing of data about an order of magnitude more complex (and thus slower). In these days where PCs are typically equipped with megabytes of memory, the authors' apparently extreme desire to conserve storage space is difficult to understand.
If storage space was indeed at a premium for some reason, it is odd that Giancola and Baker chose an implementation in which all of the bit vector code is in the form of inline functions. The inline expansion of every bit vector function call will consume code space; why not use non-inline functions to reduce the program's code size?
At a detailed level the code is not as efficent or direct as it could be. This fragment:
int i; tmp_mask = 1; for (i=1;i<N;i++) { tmp_mask <<=1; tmp_mask |=1; }could be replaced by the single line:
tmp_mask = (1 << NUM_BITS) - 1;The code for class BIT_TMP declares two BYTE arrays with a fixed-dimension of eight. One of the arrays (MASK) is never accessed except for its zeroth element (the other elements appear only as temporaries in a calculation and could be eliminated). The second array (INV_MASK) does not need to be eight characters long in all cases; its length could be computed at compile-time as INV_MASK[8/NUM_BYTES]. These two changes could save as many as 13 bytes of storage per object with no penalty.In the constructor for class BIT_TMP a temporary double (num_sub_fields) is used where an int or unsigned char would work fine. This would speed execution with no penalty.
The two operator= functions defined in BIT_TMP end with an assignment to a member variable (value). These functions are of return type void. Since BIT_TEMP objects only exist as temporaries, these assignments are useless; the object will be destroyed after the closing brace of operator+().
While I salute the ingenuity of Giancola's and Baker's idea in this article, I am disturbed by the apparent impracticality of their code. They started with a simple, real-world problem representing a Go board and evolved a very complicated, non-portable solution involving templates and nested classes. Straightforward approaches were possible. Why were they rejected?
I realize that C++ is a relatively new language and that questions of programming style are not easily resolved. Magazine articles provide an excellent means for programmers to study how another software designer approaches a problem. In this case it seems to me that Giancola and Baker went to a lot of work in order to achieve a slight improvement in notational elegance and to avoid a far-fetched possibility of accidental code misuse. This is not the kind of methodology that will solve the software crisis.
Have I missed something?
Sincerely,
Paul A. Cornelius
1261 Fernside St.
Redwood City, CA 94061Golly. Sounds to me like you favor functional notation over operator notation if efficiency is an issue. Also, you favor using the basic C data types instead of C++ class constructs if that too is more efficient. Those are the arguments I expect from a C programmer arguing against the excesses of C++.
You do indeed raise some valid objections. But I like your last paragraph best. I chose that article because it explores some serious style issues in writing C++. (The C++ standards committee is still haggling over ways to make overloaded subscript operators safer, for example. We're not alone.) The only way we'll develop good style(s) in C++ is to try out a few. pjp
L. Baker and A. Giancola respond:
While the code details mentioned by Mr. Cornelius are reasonable and necessary for peak efficiency, his stylistic comments did seem to miss the point. We will address these in the order presented in his letter.
The published code does indeed compile under both the Comeau C++ 3.0, a licensed AT&T Cfront, and Borland C++ 3.0. The article discussed differences noted in the order of function calls in these implementations, which could not have been observed if only Borland successfully compiled the code. The only reason the nested class causes any problems at all is that current implementations impose an additional restriction on the language not present in the Annotated Reference Manual (ARM by Ellis and Stroustrup). Nested class functions must be defined in the class declaration, which makes them inline. The ARM allows them to be defined at global scope (ARM 9.7 p. 187). In any case, the 'inline' directive is only a hint to the compiler (ARM 7.1.2), and may be ignored. It appears to be a bug to fail to compile because of a hint used for efficiency. The warning from Borland, that it failed to inline code we did not explicitly ask it to inline, is at worst a petty annoyance. A message that a hint has been ignored could be considered useful information. When compilers are available that fully support the ARM version of C++, this problem will disappear. We thought it better to illustrate the principle rather than what the current implementation will tolerate. We have not determined whether Cfront 3.0.1 fixes this bug.
The value of operator overloading is the ability to write things like A=B to set A, and do so in a type-safe manner. We cited as references to our article other publications that either used A.set (B) or used type coersion which would not guarantee safety. This is not a minor point, in our opinion. Operator overloading loses much of its value if one cannot use the assignment operator to assign, or if one must sacrifice safety to do so. Similarly, we desired to nest classes to hide one class from direct user access. If the reader does not agree with this premise, then the reader would not see the purpose to the article.
In a Go program, one may need to examine tens or hundreds of thousands of positions. Storage is critical, even if bought at the cost of some code complexity; i. e., reducing required storage by a factor of more than three, would be extremely valuable. We did not emphasize this point in the article, thinking it obvious, but with hindsight we should have.
If by software crisis Cornelius means the problem of producing reliable software containing millions of lines of code, by large teams of programmers, then we would claim to have made a small contribution by providing (in one case) an intuitive notation for assignment (A=B) that is type safe in place of methods that lack at least one of these features. C++, as presently designed, is probably not the ultimate solution to the software crisis. As discussed in Ellis and Stroustrup, it controls access but not visibility. Thus, C++ is not truly suitable for programming in the large. For example, if two modules, written by two teams, used the same variable name in different classes, there would be conflicts even if only one of those variables were accessible (ARM 11, p. 240).
Similarly, by including the statements:
#define private public #define protected publicbefore any include directives in a file, a user could subvert any information hiding! When any source for a class interface, even the private part, is changed and recompiled, every user of that class must be recompiled! The information hiding of the object- oriented programming paradigm is lost. Contrast this with the information hiding of Ada. If an Ada package body (the implementation) is recompiled, but the the package specification (external interface) is unchanged, none of the users of that package need be recompiled, merely relinked with the new body. Data private to the package is not only not accessible outside the package, it is invisible. These features may produce somewhat less-efficient code in some cases, but the gain in safety, and the benefits for team programming in the large, should be obvious. It would be desirable if C++, as it evolves, picks up some of these features.Sincerely,
L. Baker and A. Giancola
Dear Mr. Plauger:
Last year I was an early purchaser of your book, The Standard C Library, with the optional diskette containing the library source code. Recently I tried to use the time functions and ran into some obvious bugs in the code (e.g., xgetzone.c's reformat function formats the timezone abbreviation backwards). I called The C Users Bookstore order line to ask if an updated version of the diskette was available and was told that it was, but the price quoted was $50 for an exchange with my original diskette, or $99 for the diskette alone. I doubt if you get many takers on the latter offer given that the book and diskette are currently advertised in the magazine for only $77.95.
Needless to say, it's a lot cheaper for me to just fix the problems that I found and annotate my copy of the book, but I'm also curious why your pricing strategy for the code diskette is so prohibitive. For example, in the same C Users Bookstore advertisement the code diskette for Illustrated C adds only $10 to the price of the book. If the diskette pricing is designed as an alternative to strict enforcement of a licensing policy for commercial use of the code, then I'm lodging a protest on behalf of those of us whose use of it is strictly non-commercial.
Regards,
Brian Johnson
BJ Inc.
109 Minna St, Ste 215
San Francisco, CA 94105I agreed to a price increase for the code disk for a variety of reasons that I won't recite here. The main reason was to bring the single-copy price more in line with the quantity license terms. (You need such a license if you put the code on a multiuser system, if you put it on a network, or if you distribute copies of the source or unlinked binaries.) I knew the higher price would annoy some people, particularly individuals who just want to play with the code and don't want to have to type it in. I couldn't figure out how to please such diverse constituencies, so I agreed to take the heat. pjp
P.J.:
Two chapters into The Standard C Library and my disillusionment with C is nearly complete. Maybe now I can (belatedly) start using it as a tool instead of a god.
About copyrights I wish you had assigned the code (at least) in the book to either the standards committees or the public domain. I know Prentice-Hall needs their piece of the action, and I acknowledge that copyrights allow greater flexibility than patents in derived works. But if, having read your book, I implement a C library for, say, OS-9, how do I avoid having to put the derivation notice in my code? The algorithms, data structures, and identifier names are going to be derivative of the Standard and therefore reminiscent of your code.
Joel Rees
565 E. Mansfield Ave.
South Salt Lake City, UT 84106-1205All a copyright covers is unique expression. If you can show that the choice of algorithms, data structures, and/or identifier names is natural, or derives directly from the C Standard, similarities to my code don't matter. Crib anybody's code directly and you infringe, however. (I managed to replicate UNIX under the watchful gaze of AT&T, and after having had access to UNIX source, without infringing their copyright. It can be done.)
The problem I've stumbled into is the one I outlined in my previous response. I started out simply to make "exemplary" code for all to see and enjoy. Before I knew it, I had created another marketplace among people who need a Standard C library. Now it seems that whatever I do, I upset somebody. pjp
Editor:
I recently purchased The C Toolbox book by William James L. Hunt (Addison Wesley), with its "Ready To Run Programs in Turbo C, Microsoft C, and Quick C." While quickly perusing the book, I noticed some serial-communication programs that looked interesting. I committed myself to purchase the book.
After having purchased the book, I examined the programs only to find out that they referred to other functions which were not available anywhere in the book. They do, however, offer a source disk package which I suspect must have these functions in it. I feel that the book, by itself, is completely useless and is misrepresentative.
I feel that other potential buyers of this book should know this.
Bill Casey
Woodside, NY