Dear Mr. Ward:I'm writing to complain because The C Users Journal does not have a nude centerfold. Also, I think that every subscription should include a bottle of rum and a free compliler. Also ...
The above tongue-firmly-in cheek comments illustrate a common thread I see running through the complaint letters you publish: they all want this magazine to be something other than what it is. From what I have seen, CUJ is not a magazine for anyone who expects to learn C in ten minutes a day (and has only written in Basic), nor is it intended to focus on one narrow, obscure aspect of the language. I find this magazine to be illuminating, interesting, informative, and a bit eclectic. I like it; of the several periodicals I read, CUJ is the only one I always read cover-to-cover and in excruciating detail. The information I get from this publication helps me in my mundane, MS-DOS utility writing, my multiprocessor operating system design, and my machine intelligence research. In short, it covers a hell of a lot of ground for one magazine, and I am quite impressed. It's more than worth the money, and it is the only magazine to which I subscribe.
Of course, the centerfold would be nice.
Very truly yours,
Ian S. King
520 SW Yamhill #430
Portland, Oregon 97204Thank you, thank you, thank you. You just made my day. rlw
Dear Mr. Ward,
Finally! I was delighted to see the discussion of arrays of pointers to functions in Rex Jaeschke's column (March, 1990). An array of pointers to functions is one of the most powerful constructs available in the C language, yet it is almost never discussed in the trade journals or used in code.
We have been using arrays of pointers to functions (we call them procedure tables) for 4 years. The uses for them go way beyond Rex's discussion. They give the programmer the capability to treat code as if it were data, and this opens up an entirely new world for system design.
As a brief example, consider the following task. Generally when a program is initializing, it performs a series of tasks such as opening files, allocating memory, and initializing communications ports.
Most of these steps will require some sort of error checking to make sure that they were properly executed. If any error is encountered, the program must stop execution and handle the error in a civilized manner. In addition, all errors must be handled in exactly the same manner.
A traditional method for performing this would involve one very large function with the steps coded one after the other. This method is bug-prone and difficult to maintain.
Using a procedure table greatly simplifies this chore. The various initialization tasks are divided up into bite-size pieces and each is given its own function.
(See the code in Listing 1. )
The task of the function initialize() is to call each of the functions that is in the procedure table init_funcs(). It calls them by looping through the table. If any of the functions encounters an error, it returns a unique non-zero return code. This causes initialize() to immediately return the value that it received. The function that called initialize() then handles any error based on the unique error code returned to it.
When a new task must be performed in the initialization, we just put its address into the procedure table and it will be handled in the same systematic manner as the other tasks, without the fear of side-effect bugs. Or if we find out that we must rearrange the order of execution of the tasks, we just rearrange the declaration of the procedure table.
This simple example still does not do justice to the power of procedure tables, but it should give a starting point to anyone who is interested.
I would also like to offer one minor correction to Rex Jaeschke's column. He states that the overhead of a function call could be avoided in his example by indicating to the compiler to generate inline code for the functions called by the statement:
(*funtable[pnode->objtype] (pnode->pobject);There is no way a compiler could generate inline code for this statement. The reason is that the compiler does not know the address referenced by this statement at compile time because pnode->objtype can be changed at will during runtime. Also the addresses stored in funtable could be changed at runtime.
If you wish to do some further reading, the only other article I know of that discusses this subject is "C Procedure Tables", in the August 1989 issue of Dr. Dobb's Journal.
Keep up the good work. I love your magazine.
Sincerely,
Tim Berens, President
Back Office Applications, Inc.
6691 Centerville Business ParkwayThanks for the kind words. Others have commented that they appreciated Rex's discussion of jump tables. rlw
Attn Robert Ward:
Subject: Feature not Bug
In reply to Mr. Alexander Vladimirovich Pavlov's letter (in the April 1990 edition of CUJ P. 140), Mr. Pavlov is describing an 'option' of Turbo C rather than a 'bug'. In the Turbo C user's guide it describes a way to override the standard library files in the project file. To override the standard library, all one needs to do is place a special library name anywhere in the list of names in the project file. The name of the library must start with a C, followed by a letter representing the model (such as a 's' for the small model); the remaining characters, up to six, may be a combination of letters for a file name. However, an explicit .LIB extension must be used. See page 36 of the Turbo C user's guide for more information.
Grant Larkin
Borland International
Technical Support Department
1800 Green Hills Road
Scotts Valley, CA 958066Thanks for the pointer. It's nice to know that the folks at Borland are listening. rlw
Gentlemen:
Some time back, you sent me an invitation to join the C Users Group and subscribe to your journal. I have delayed joining for any number of reasons. This past weekend I was in Detroit, and happened upon a copy of your publication. I have only read one article from the magazine (Dr. C's Pointers) and I am impressed. While I do not write operating systems or data base applications on a routine basis, I am proficient enough to develop significant applications. I am often skeptical of offers for magazine subscriptions, as they provide only a few articles per year which are truly worthwile.
Enclosed, please find my subscription.
I wonder if you could also tell me how to order (and the cost of) a previous issue. I would like to purchase the Feb 90 issue.
I must comment on the disgruntled reader/subscriber who found the price increase an assault to his wallet (We Have Mail - March '89). I too side with you. If you offer this kind of material in each issue, no one should take exception to your policies and price structure. If you were to go out and purchase a text, you will pay nearly as much (and possibly more). Even when these are titled as "advanced", you must often wade through pages of useless, basic material. Keep up the fine work.
Sincerely,
Gregory L. Filter
87 Lathrop
Battle Creek, MI 49017Gee, is it my week or what? Thanks much again.
Dear Robert,
I was disappointed to find that this month's Obfuscated C Code contest became instead a Totally Obscured C Code contest. I was even more disappointed to see that the wrong version of my Threads source was printed last month, and that no errata appeared this month. Has changing to a monthly schedule hurt your quality control that badly?
I take it that I am not the only disappointed party, since I have gotten correspondence from as far away as Saudi Arabia asking about problems with the (wrong) Threads code. So let me try to clear up some common confusions for your readers. First, if you are having trouble, get the right version of the code from CUG (Volume 306). The version printed with the article was an early draft. Second, if your compiler is not ANSI, you will need to remove the prototypes in THREADS.H, replace void declarations with white space, and modify THREADS.C to use old style function definitions, rather than protytypes. Third, be sure you know your system. My code assumes that the stack grows towards low memory, but some systems (e.g. ATT3B2) do it the other way round. If so, you will need to reverse the ThProbe macro and the "not enough stack" test in ThInit. Some other systems (e.g. VAX) keep close guard on the stack, and won't allow a longjmp() to a deeper point in the stack. Study your system's function call protocol and setjmp() and longjmp() code if you have any doubts about whether Threads will work.
To get some lemonade from this lemon, the differences between the draft and final versions of Threads may be instructive. The draft version maintained a parent field for each thread, a vestige of the UNIX origins of my design. The parent/child concept in UNIX is mainly for managing resource ownership, whereas my threads share all resources, so I removed the relevant code in the final version. This led to a smaller ThTabl structure, and greatly simplified the logic in ThInit. The draft version maintained a run list for a simple round robin scheduler. I found that I rarely used this feature, but usually needed some more specialized scheduler. So I replaced it with a simple ThNext macro, further reducing size and complexity. Finally, the draft version tests input parameters and returns error codes. Since most cases of invalid parameters would indicate severe program errors, I replaced most of these tests with the assert() macro. Once you are certain that only valid parameters can be passed you can define NDEBUG to remove the tests. The result of all these changes was a much smaller and faster kernel.
Sincerely yours,
Gregory Colvin
680 Hartford
Boulder, CO 80303Ah, I knew it was too good to last. This I don't want to talk about. This I really don't want to talk about.
But, I suppose I must.
Yes, we have made a few serious mistakes recently. For one, we used the wrong version of your code. We have placed the correct version on the code disk for that issue. Second, in a masterly exhibition of disorientation, I put the Publisher's Forum and the cover banner from the May issue on the April issue. (I had just finished editing the April issue's obfuscated code story at the time.) The amazing part of this screw-up is that the "dummy" version of the book and proofs of the column were reviewed by four others without triggering any warning bells.
Yes, some of these mistakes are related to work-load, and we've added staff to address those problems. Some are just "transition glitches", and we're working deliberatety to correct those. Please accept my abject apology.
Jeez, this is embarrasing. rlw
Dear Robert:
I've subscribed to the C User's Journal for a couple/three years.. have definitely missed your "How to do it in C" column recently. Now I see what you've been up to.
"Tech Specialist" sounds like a rank in the armed services, but I'll give it a try anyway. Perhaps this will be the platform from which you will launch the long-awaited swimsuit issue....
Scott Swanson
Donna keeps nagging me to do more columns. I keep collecting ideas. Now all I need is some more time. So why are we starting another magazine ...?
I can't promise a swimsuit issue (Donna still hasn't approved it), but I can promise that we'll do our best to publish technical information you don't get anywhere else. rlw
Dear Mr. Ward:
As a "learning" C programmer, I was immediately engrossed in studying and coding Leor Zolman's mini-database program (April, 1990,p.69+). Last year I wrote a program that had essentially the same goal as Mr. Zolman is addressing. Seeing his slick and efficient method of handling I/O in data structures makes my approach a candidate for your obfuscated C code contest.
I am more than grateful for what Mr. Zolman has already taught me, and I look forward to the remaining articles in the series. I hope, too, there will be many more tutorial features by Leor Zolman in future issues of the CUJ.
Sincerely,
John Ullmer
Data Archiving Services
P.O. Box 160637
San Antonio, Texas 78280-2837You just made Leor's day.
Leor has another installment in this issue. I too think he's done a good job, and I plan to have him do more. Would you like to suggest a particular topic? rlw