Columns


Questions & Answers

Using Code Generators For Creating C Code

Ken Pugh


Kenneth Pugh, a principal in Pugh-Killeen Associates, teaches C language courses for corporations. He is the author of C Language for Programmers and All On C, and was a member on the ANSI C committee. He also does custom C programming for communications, graphics, image databases, and hypertext. His address is 4201 University Dr., Suite 102, Durham, NC 27707. You may fax questions for Ken to (919) 489-5239. Ken also receives email at kpugh@dukemvs. ac.duke.edu (Internet).

Q

I've read many of your books and articles. They are very enlightening, thank you. I'm posting this for a friend who is a business manager. He's been given the task of writing C programs, but he doesn't know C that well. He's heard that a code generator might help. What is it? Is it worth getting? Where can he get one if it is worth while? Thanks for your time in reading this note, I know you're a busy individual.

Steve Kohut
New York

A

Code generators ease the creation of screens and reports. They go a step beyond demo programs, such as Dan Bricklin's, in not just demonstrating a user interface, but also in turning it into C code. That may complete the input portion of your program, but you still have to write the process portion. For example, the placement and colors for name and address fields in a mailing list program can be created by the generator. But any custom functions (such as comparing the ZIP code to the state for agreement) and the disk operations for storing and retrieving the names must be written by you.

There are several available from the companies that sell programming tools (such as the ones advertising here in The C Users Journal). The only one I have used for the C language are C-scape's Look and Feel from the Oakland Group (now Liant). It was a version from 1988, so the product may have additional features by now.

You should look at the model that the screen package uses — the numbers and types of functions. If you can understand the model, then modifying the source that is created by the package will be simple. C-scape has a fairly simple model. It is easy to determine from the code where a particular field is being input.

On a similar note at the recent C-forum, I had the opportunity to see a demo of Liana, by Base Technology (1543 Pine Street, Boulder, Colorado 80302; (303) 440-4558). This is a C-like language interpreter with an object-oriented approach to MS Windows. You can not only create windows, but perform many standard operations (such as text editing, printing, DDE). It is not a code generator in the standard sense of the term. But it is such an easy-to-use interface to Windows that it yields the same benefits for the C programmer trying to create a Window program.

By the way, there are other C code generators that are used for special purposes. If you are doing any work with language processing, I heartily recommend lex and yacc. If any reader knows of other generators for any purpose, please let me know and I'll pass them along.

Q

I've been working in C just a short while and only now have had to use pointers. The following mini program (Listing 1) is a slight adaptation of an example program copied from C Primer Plus by Mitchell Waite et al. It yields different results depending on the memory model that is used during the compilation, as shown in Figure 1 and Figure 2. Perhaps it's only a printf bug (or feature) but it's got me puzzled.

As I understand it, the three models that don't work use either far or huge memory pointers, whereas the three that do work use near pointers. With that in mind I attempted to specify the use of near pointers in either or both of the int declaration lines (i.e. int near *ptr) while the compiler was defaulting to one of the three larger models. The results were the same, that is, it worked incorrectly.

Is this a documented problem or am I doing something stupid or am I misusing the Turbo C compiler or what? Any help would be appreciated.

Tom Frank
Austin, Texas

A

With the %u format specifier, you are asking printf to print an unsigned integer. The size of a large memory model pointer (or near pointer) is two bytes, or the size of an integer. When you compiled it with the small model, the size of the pointers being passed to printf agreed with that designated by the format specifier.

The size of a large memory model pointer (or far pointer) is four bytes, or the size of a long integer. When you used the large memory model, the size of the pointers was twice that specified by the format. Each half of the pointer values that were passed was treated as an integer by printf.

On a PC, the bytes of an integer or pointer are in reverse order. So the values that were printed out represented the two least significant bytes followed by the two most significant bytes. The value of ptr was really equal to

6207 * 65536 + 4056
You can see the same phenomena if you print longs on a PC using the integer format, as shown in Listing 2.

You can avoid the memory model problem by using the new ANSI format specifier %p. This prints out the value of the pointer using the size based on the memory model specified at compile time.

Q

What books would you recommend as the best for intermediate to advanced programming of 2-D and 3-D animation and saving and loading PCX and GIF picture files in Microsoft C v6? If none of the books covers v6 is there anything for QuickC v2?

Could you also recommend a book on BIOS, DOS, and hardware addresses for programmers?

Would I be better off using C++ for graphics programming?

Bruce Balstad
Hoffman Estates, IL

A

I have to admit I have simplified my life when it comes to graphics. I wrote my own PCX loader originally using the PCX file documentation from Z-Soft. Later I bought Essential Graphics (from Essential Software, 76 So. Orange, So. Orange NJ 07079 (201) 762-6965). It handles most all the options in PCX files. To handle all other graphics, I simply convert them to PCX using Hijaak.

Essential Graphics has lots of drawing functions. I am not wild about the names they have used, but they work. They are a little slow for animation.

In regards to DOS, pick up a copy of MS-DOS Programmer's Reference book. It's complete (except for a few undocumented calls). For the BIOS, the IBM Technical Reference manual is available (at a bit of a price). The earlier versions included the assembly source code listings. I haven't bought one recently.

Perhaps our reader's have some suggestions for graphic books.

Q

I am currently working on a business application that involves a large amount of reading and writing to inventory style data files but due to the fact that most of my knowledge comes from books and not experience, I am running into a problem that is setting me behind schedule. The problem is that I just can't seem to find the correct codes that will allow the user to delete an item from the inventory file. I have tried writing the hex value of the delete key to the selected bytes of the file, but instead of deleting the chosen character(s) the program displays the ASCII representative of the delete key to the selected bytes.

Is there any simple solution to this problem that will allow me to accomplish this task or do you know of any books that would help me to find out what I am doing wrong?

Your help would be greatly appreciated. I hope to hear from you soon.

Michael Messuri
Moline, IL

A

This is a tough one, since you didn't specify the database that you are using. On many database systems, a record is marked as deleted if the first byte is a special character (e.g. OXFF or OX7F). When the data file is read sequentially (without an index), any records with this byte are usually ignored by the database. If the data file is read using an index, then when the record is accessed, the database may return the record as a valid one. It would be up to your code to check for deleted records.

If the data file is re-indexed after a deletion is made, then the deleted record will not be indexed. If the data file is compacted, then the record will be physically deleted.

Q

I have a program problem that is driving me crazy. I figure the answer should be quite easy for a C programming veteran like you. In a BASIC program (please don't give up on me yet) I use the following routines (Listing 3) to save or load the Hercules graphics screen to/from disk.

I would like to do the same thing in C. My routine (Listing 4) does save a 32767 byte file however, it is not the Hercules screen. What am I doing wrong?

I feel very stupid asking you about this. This one has me bewildered. Your help is appreciated. Thanks.

James A. Gant
Oklahoma City, OK

A

Don't worry about feeling stupid. That happens to me sometimes when I stare at a block of code for a few hours and realize that "for lack of a semicolon, a program was lost."

Your code appears on the surface to be fine. You must compile it with the large memory model. If you do not, then the library functions will use the small memory model. And the header files that will be included are those for the small model.

If the compiler you are using has prototypes, then the following will occur. Inside <stdio.h> is the following statement. (To simplify, I've substituted int for size_t).

int fwrite(void *address, int size, int count, FILE *file_pointer);
Inside your program, as you have written it is the statement

fwrite(hga_buff, 1, 32767, fp);
Since a prototype is in scope, and the parameters are assignment compatible, then the parameters will undergo a silent conversion. The only one that does not match is the first one. So it will be as if you had written

fwrite ( (void near *) hga_buffer, 1, 32767, fp);
Note that the void * address of the prototype will be interpreted as a near pointer, since the file is compiled in the small model. The data that is written out would start at location 0 (the lower order two bytes of the address).

Now you should get a warning message about "suspicious pointer conversion" since you are converting a far pointer to a near pointer. But the warning is not required by ANSI and if you have warnings turned off, you won't see it.

If the compiler does not have prototypes, the conversion will not take place, but the writing to the file should have failed.

main () Placement

I'm really behind on my reading, so I'll assume your incomplete answer in the July issue of The C Users Journal, pages 106 and 107, has already been pointed out. But just in case... The question was, why are functions normally

main ()
{}
func1 ()
{}
func2 ()
{}
func3 ()
{}
but sometimes

func1 ()
{}
func2 ()
{}
func3 ()
{}
main ()
{}
In days of old, before prototyping in ANSI C made function declaration common, there was a problem with pointers to functions. The compiler had to know of the function before it would allow a pointer to it. This could be handled by

main()
{
   int func1 (), func2();
   float func3() ;
   . . .
   Code
   . . .
}
But it is more often handled, such as in CU, by coding the functions to be pointed to by function pointers before the code that will set pointers to said functions.

There also was the quirky thing in many compilers that any variables listed outside a function were considered global from that point on down. So one could have functions that were not supposed to be able to access global variables that other functions in this file were enabled to do so. (Other files had access to all non-static globals in this file.)

I'm assuming that Lyle O. Haga was looking at old code. I haven't seen these techniques in common use since C/UNIX stopped being mostly a PDP/11 phenomenon.

Doug Parsons
Boston, MA

Thanks for your comments. Actually that wasn't a quirky thing in the compiler. In K&R, page 206, the rule for external identifiers was "from the definition to the end of the source file in which they appear." That simplified the compiler since any variable name that was found in a function had to have been declared prior to its use.

The ANSI rules state that the external definition has file scope. This means that it can be placed anywhere in the source file.

In reality, most people place all external definitions at the head of the source file. Relying on the scoping rules of K&R as you described makes the maintenance a bit of a nightmare. (KP)

DLLs for DOS

In the September 1991 issue of CUJ, David Qualls asks about support for "dynamic linking" in DOS. Although it currently supports only UNIX, and not DOS, he might want to take a look at dld by W. Wilson Ho. dld is (quoting its documentation) "a library package of C functions that performs dynamic link editing."

Programs that use dld can add compiled object code to or remove such code from a process anytime during its execution. Loading modules, searching libraries, resolving external references, and allocating storage for global and static data structures are all performed at runtime. dld is now available for VAX, Sun3, SPARCstation, Sequent Symmetry, and Atari ST. dld is distributed under the terms of the GNU copyright agreement (and can be obtained from most GNU archive sites), so source code is freely available.

It might be possible to implement the code under DOS, but doing so would doubtless require a thorough understanding of the structure of DOS .OBJ, .EXE, and .LIB files. Perhaps some keen programmer somewhere would like to volunteer?

Eric Zurcher
Canberra Australia

Any volunteers? (KP)

Memory Resident Utilities

In response to Moses Mwarari Maina's question in the September, 1991 issue, I know of two different sources for writing TSRs. The first is Turbo C Memory-Resident Utilities, Screen I/O and Programming Techniques, by Al Stevens from MIS Press. It has two chapters with about 80 pages on the subject. The second is the TesSeRact TM Ram-Resident Development System, from Innovative Data Concepts, Inc., 122 North York Road, Suite 5, Hatboro, PA 19040. Their order phone number is 1-800-926-4551. I have only played with these and have not had time to use them myself.

Geoffrey Probert
Broomfield, CO

This is in response to the letter from Moses Mwarari Maina of Nairobi, Kenya which was published in the September 1991 issue of CUJ. Mr. Maina might benefit from the book Turbo C: Memory-Resident Utilities, Screen I/O, and Programming Techniques, written by Al Stevens and published by MIS Press in 1987. MIS was located here in Portland; I just tracked them down. They are now a division of Henry Holt Company, 4375 West 1980 South, Salt Lake City, UT 84104. Their WATS number is 800-408-5233. They still publish this book.

Beginning with Chapter 4, chapter titles are: General- purpose Functions, Screen Windows, The Windows Function Library, Context-sensitive Help Windows, Data Entry Windows, the Windows Text Editor (aside: Al also did a series, in DDJ I believe, on TWP: Tiny Word Processor), Windows Menus, Memory-resident Programs, and Building Turbo C Memory-resident Programs.

Another source I can recommend from personal experience is IDC (Innovative Data Concepts) at 122 North York Road, Suite 5, Hatboro, PA 19040. They developed the shareware TesSeRact TSR library and purchased Mike Smedley's superb CXL windowing/menu/data entry/general purpose C function shareware library (it's now TCXL version 5.52). I hope this helps Mr. Maina. Kudos to you and the rest of the CUJ team for a valuable publication

Richard B. Shepard

Thanks to you both for your sharing of the information. (KP)