home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-08-05 | 81.8 KB | 2,403 lines |
-
- Issue C News 1
-
-
- *--------------------------------------------------------------*
- | C NEWS - International C Electronic Newsletter/Journal |
- | "Dedicated to the Art of C Programming" |
- | |
- | Founded 12/27/87 |
- *--------------------------------------------------------------*
-
-
- Table of Contents
-
- The HEAP: By Barry Lynch ............................... 2
-
- The STACK: By Jim Singleton ............................ 3
-
- String Arrays by Paul E. Castle II ....................... 4
-
- Review: The ECSTR Library by Paul Hinds .................. 8
-
- LABEL.C -- A Simple Label Program by Jim Singleton......... 10
-
- Beginner's Column by Wayne Dernoncourt ................. 19
-
- Where's That Number? by Jim Singleton ................... 24
-
- Portability Coding Issues ............................ 26
-
- New PD/Shareware Releases by Barry Lynch ................ 37
-
- Article Submission Standards ......................... 39
-
- How to get hold of us here at C............................ 40
-
-
-
- "C News" is an Electronic Journal published from time to
- time. The subject of C News is the C programming language,
- as well as any derivatives like C++. All readers are
- encouraged to submit articles, reviews, or comments for
- submission. C News is freely distributed, but can not be
- sold for a profit and cannot have a charge assessed to
- cover distribution costs. All articles and reviews become
- the property of C News and cannot be included in other
- publications without written permission from the C News
- Editorial Staff. This publication is Copyrighted under
- U.S. Copyright Law.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 2
-
-
- =================================================================
- The HEAP: By Barry Lynch
- =================================================================
-
-
-
- It's been quite awhile since an issue of C News has been
- published, and it is with some pride that Dan, Wayne, Jim and I
- bring this 19th issue to you.
-
- Over the last few months I have had the pleasure of selling
- a home in Virginia and relocating and purchasing a new home in
- the Dallas-Fort Worth area. For those of you that own homes or
- have been through the relocation process, you probably
- understand the stress and upheaveal that a relocation brings.
- Finally, after months of planning, packing, travelling and
- unpacking I have settled down and look forward to more frequent
- issues of C News.
-
- This issue of C News brings some articles that were
- submitted quite a few months ago and have been patiently waiting
- for the next publication date. There are articles on C
- portability problems, the continuation of Jim Singleton's
- article on software development, another one of Wayne's
- Beginner's columns and a piece on shareware.
-
- The last few months have seen the release of a major
- upgrade to one of the bigger C compilers (Microsoft), a major
- release from one of the original DOS C compiler vendors
- (Lattice) and new compiler to add more fuel to the compiler wars
- (Topspeed). Over the next couple of months, Dan, Jim Wayne and
- I will be bringing you some of our thoughts on these various
- compilers as we all use different ones in our daily programming
- exploits.
-
- This issue of C News is not the last and will be followed
- by Issue 20 sometime in the early fall. If you have ideas for
- articles or comments on the style that are constructive, we
- welcome them. It should be noted that we are not striving to be
- a "professional" publication, just a fun project by a couple of
- guys in Virginia, and a misplaced "Brit" in Texas.
-
- C ya in the next issue.
-
- Barry
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 3
-
-
- =================================================================
- The STACK: By Jim Singleton
- =================================================================
-
-
-
- When Barry and I were discussing the editorial for this
- issue of the C News, Barry suggested that I write one as well
- since Dan, Wayne and I are still in the Washington, D.C. area.
-
- Barry forgot to mention that the last few months have also
- seen Borland come out with their first C++ compiler. While none
- of us at C News are experienced C++ programmers, we would like
- to cover C++ in the C News. Anyone interested in submitting an
- article, please contact Barry or myself.
-
- At the end of each issue we tell you how to contact us here
- at the C News. However, in light of all the changes since issue
- 18, we decided to mention it here as well. You can contact us
- through:
-
- The C News
- P.O. Box 15314
- Arlington, VA 22215
- USA
-
- FidoNet: 109/138.1 (Jim)
- Fidonet: 1:124/3116 (Barry)
- North Texas C Programmers Board: 1-214-442-0223 (Barry)
-
- CIS: 71540,2677 (Jim)
-
- MCI Mail: 272-8067 (Barry)
-
- Internet: dbk@cs.umd.edu (Dan)
- UUCP: ...!uunet!mimsy!dbk
-
- European C News Distribution Point: 011-3185642891
- Sysop: Rob Koel
-
- Feel free to contact us with any ideas, comments, or
- criticisms you may have.
-
- Jim
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 4
-
-
- =================================================================
- String Arrays by Paul E. Castle II
- =================================================================
-
-
-
- Unfortunately, error conditions are a fact of life. Any
- program you write, no matter how small, carries with it the
- potential to produce an error. A good program attempts to trap
- errors when they occur and gracefully handle them.
-
- Error handling, however, can produce masses of extra code,
- extreme confusion, and sticky maintenance problems if not
- implemented smartly.
-
- Consider the following line of code:
-
- fileptr = fopen(infile,open_mode)
-
- This is a very common and simple action - open a file.
- However, as written, it is fraught with danger. Suppose the
- open fails? The FILE pointer "fileptr" is assigned the "NULL"
- value. Any attempt to use "fileptr" will, at best, cause a
- program crash, or worse, a system crash. The solution is to
- trap the error:
-
- if((fileptr = fopen(infile,open_mode)) == NULL) {
- printf("Could not open INPUT file.\n");
- exit(1); }
-
-
- This code traps the error, prints an error message to the
- screen, and terminates processing.
-
- Now, allow me to digress from the main topic for just a
- moment and talk a little about the line "exit(1)".
-
- The "exit()" function is part of the standard library. The
- prototype can be found in "stdlib.h" and "process.h" and takes
- the form of:
-
- void exit(int status)
-
- "exit()" flushes all buffers for files open for buffered I/O,
- closes all files, and terminates the program returning the "int
- status" to the calling program or the system. A "status" value
- of "0" traditionally means "no error". Error conditions are
- indicated by a non-zero value. Keep this in mind as we
- proceed.
-
- Now, let's assume you have seven files that your program
- opens. That means seven "fopen" statements and twenty-one lines
-
-
-
-
-
- Issue C News 5
-
-
- of code like that above. Furthermore, let's assume that you
- have seven other error conditions for which you check. Each
- check includes an "if" statement, a "printf" statement, and an
- "exit" statement.
-
- You should be able to see by now that you have a
- substantial amount of code invested in opening files and error
- handling. But, you can reduce the amount of code, and the
- headaches associated with maintaining it, substantially by using
- string arrays. Watch.
-
- To handle the errors, create an array like this:
-
- char *error_msg[] = {
- NULL,
- "Error message one text.\n",
- "Error message two text.\n",
- "Error message three text.\n",
- "Error message four text.\n",
- "Error message five text.\n",
- "Error message six text.\n",
- "Error message seven text.\n",
- "Error message eight text.\n" };
-
- The above array is an array of pointers to strings. The
- first entry, "error_msg[0]", is NULL (or NO ERROR).
- "error_msg[1]" is the string "Error message one text." and so on
- to "error_msg[8]".
-
- Once the array has been created, you can now create a
- routine called "error_exit". You would declare the function
- like this:
-
- void error_exit(int errnum)
-
-
- The code for the routine would look like this:
-
- void error_exit(int errnum)
- {
- if(errnum) {
- printf("%s",error_msg[errnum]);
- exit(errnum);
- }
-
-
- To use "error_exit", the invoking function calls the error
- routine passing the index value associated with the desired
- error message. The "if(errnum)" determines if an error exists.
- A "0" (or NO ERROR) would resolve to false and the function will
- return to the caller taking no action. Obviously, you would
- never call "error_exit" with a value of zero. A non-zero value
-
-
-
-
-
- Issue C News 6
-
-
- would resolve to true and the "printf" statement would print the
- text pointed to by "error_msg[errnum] and the "exit" statement
- will return the value of "errnum" to the calling program or
- system.
-
- Using the above example of the "fopen", we would rewrite
- the code in this way:
-
- if((fileptr = fopen(infile,open_mode)) == NULL)
- error_exit(1);
-
-
- This would result in the error message "Error message one
- text." being printed and the value of 1 being passed to the
- calling program or system if an error occurs.
-
- This method keeps the duplication of code to a minimum and
- allows all error handling to be done from a single function. As
- the code changes or more error conditions are checked for, it is
- a simple matter to add error messages to the array or to change
- existing messages. This saves you from having to search
- thousands of lines of code for elusive error text to change.
-
- Now, we have solved the problem of error handling, but we
- still have seven different "fopen" statements in our program.
- We can use a string array to solve this problem, also.
-
- If we create the following arrays:
-
- FILE *fileptr[7]; /* array of file pointers */
-
- char *file_table[] = { /* array of file names */
- "FILE1",
- "FILE2",
- "FILE3",
- "FILE4",
- "FILE5",
- "FILE6",
- "FILE7"; }
-
- we can rewrite the "fopen" code to handle all seven files.
-
- if((fileptr[file_ndx] = fopen(file_table[file_ndx],open_mode)) == NULL)
- error_exit(1);
-
-
- The invoking function would call the open routine passing
- the index pointing to the desired file name in the
- "file_table". That same index is used to access the array of
- file pointers so that pointer "fileptr[0]" would point to
- "file_table[0]", or FILE1 in this case, and so on.
-
-
-
-
-
-
- Issue C News 7
-
-
- If you wished to open all the files at one time, you could
- do so in this manner:
-
- for(file_ndx = 0;file_ndx < 7;file_ndx++) {
- if((fileptr[file_ndx] = fopen(file_table[file_ndx],open_mode)) == NULL)
- error_exit(1); }
-
-
- As you can see, string arrays can be used to add
- flexibility to your code and help make "generic" functions.
- They are a powerful tool and with a little thought and a little
- imagination you can do amazing things with them.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 8
-
-
- =================================================================
- Review: The ECSTR Library by Paul Hinds
- =================================================================
-
-
-
- Boilerplate
-
- The .ZIP file is about 65K and is dated 5/86 (as are all of
- the files) even though all of the files have internal comments
- indicating dates of April/May/June, 1984. The file is stated by
- the author as being placed in the public domain although he does
- request that it not be put to any "military" use. I've seen this
- file on MANY boards in the DC area, so assume it is fairly
- readily available wherever you are.
-
- General Description
-
- With over 60 functions (74 files total, including .H files
- and some others), all of which are concerned with string
- manipulation (it is my assumption that ECSTR => Extended C
- STRing), this is a wealth of source material for anyone who
- wants their own source library of string manipulation routines.
- The following files are included:
-
- READ ME GETOPT C STREND C STRREV C
- INT2STR C STRFIELD C STRRPT C
- CTYPES DEM MEMCCPY C STRFIND C STRSPN C
- MEMCHR C STRKEY C STRSUFF C
- GETOPT 3 MEMCMP C STRLEN C STRTOK C
- XSTRING 3C MEMCPY C STRMOV C STRTRANS C
- MEMMOV C STRNCAT C STRTRIM C
- ASCII H MEMRCHR C STRNCMP C STRXCAT C
- CTYPES H MEMREV C STRNCPY C STRXCPY C
- MEMORY H MEMSET C STRNEND C STRXMOV C
- STRINGS H MEMTRANS C STRNLEN C STRXNCAT C
- _STR2MAP H STR2INT C STRNMOV C STRXNCPY C
- _STR2PAT H STRCAT C STRNREV C STRXNMOV C
- _STR2SET H STRCHR C STRNRPT C SUBSTR C
- STRCMP C STRNTRAN C _C2TYPE C
- BCOPY C STRCPACK C STRPACK C _STR2MAP C
- BFILL C STRCPBRK C STRPBRK C _STR2PAT C
- BMOVE C STRCPY C STRPREF C _STR2SET C
- BZERO C STRCSPN C STRRCHR C
- FFS C STRCTRIM C STRREPL C
-
-
- Review
-
- This collection is not exactly for the faint of heart or
- the rank beginner (although anyone who has created, compiled,
- linked and run even a few C functions can deal with it). Only
-
-
-
-
-
- Issue C News 9
-
-
- source code is provided, with excellent block comments in each
- source module and a modest, but illuminating, README file.
- Mildly oriented towards VAX machines but conditional
- compile/assembly statements make everything available to non-VAX
- users.
-
- I've stripped out the heart of several of the routines
- (dumping the conditional stuff since I don't have a PDP-11 or a
- VAX) and have have had no problem reformatting them to compile
- under Turbo C (2.0). I see no reason why users of other
- compilers should have any more trouble than I did.
-
- Most or all of the 30 or so library functions for string
- manipulation included in Turbo-C 2.0 can be found here, as well
- as ANOTHER 30 or so, and since the source code is provided, this
- is an excellent opportunity for those of you who want to have
- LOTS of string functions available and/or those of you who want
- source code so you can "do your own thing". I doubt that many
- compilers (if any) provide anywhere near this extensive a
- package of string functions. And, of course, the price is
- right.
-
- This is a useful package, regardless of its age. There is,
- of course, the fact that since it is an unsupported package,
- you've got no one to yell at if anything goes wrong, but hey,
- the source code is there and what more can you ask for?
-
- COMPATIBILITY: written to run under ANY version of UNIX.
- Author has wisely chosen compatibility over rationality (in
- function names and argument lists) --- if this sounds strange,
- then you might be unfamiliar with the MAJOR headaches which
- accompany rational but incompatible tools. The READ.ME file goes
- into some discussion about compatability with UNIX functions.
-
- ANSI: this was done LONG before the ANSI standard was
- introduced and I have made no attempt to determine ANSI
- compatibility.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 10
-
-
- =================================================================
- LABEL.C -- A Simple Label Program by Jim Singleton
- =================================================================
-
-
-
- Introduction
-
- The other day at work, I came across a simple diskette
- label program, written in BASIC. The program printed a simple
- four line label composed of a title, name, date and two comment
- lines:
-
- +-------------------------------+
- | Personnel Payroll Data, Disk |
- | Rufus Jackson 6/23/90 |
- | This is the data for use by |
- | the payroll audit team. |
- +-------------------------------+
-
- While the program worked and did what it was supposed to do,
- there were a couple of things I didn't like about it:
-
- - The name and date were hardcoded into the program,
- so they had to be edited if they were to be changed.
-
- - The program wasn't compiled, which made it easy to
- edit the name and date, but loading BASIC first
- slowed the program down.
-
- - The program did not exit back to the operating system,
- leaving the user in BASIC.
-
- - The program only printed one label at a time, which
- was okay if you only wanted one label, but was a
- pain if you wanted several. I didn't mind that it
- would not print multiple copies of a label; but, if
- I want to label ten different disks, I don't want to
- load and run the program ten times.
-
- Rather than modify the existing BASIC code, I figured I'd write
- it in C. (The fact that I didn't have a BASIC compiler had
- nothing to do with this decision. :-) Besides, I often hear
- people just starting out in C ask how to send output to the
- printer.
-
- A short time later, I had a working program:
-
-
-
-
-
-
-
-
-
-
- Issue C News 11
-
-
- /* LABEL.C -- Print out a diskette label. Designed for
- an ALPS P2000G printer, it should work on any Epson-
- compatible printer. */
-
- #include <stdio.h>
-
- FILE *printer;
-
- void main()
- {
- /* Define arrays to hold each item of data. */
- char name[15], title[28], comment1[28],
- comment2[28], date[8];
-
- /* Open a file pointer to the printer. */
- printer = fopen("LPT1", "w");
-
- /* Prompt the user for each item of data and read
- in the data. */
-
- printf("\nPlease enter the title: ");
- gets(title);
- printf("\nPlease enter a name: ");
- gets(name);
- printf("\Please enter the date (MM/DD/YY): ");
- gets(date);
- printf("\nPlease enter the first comment: ");
- gets(comment1);
- printf("\nPlease enter the second comment: ");
- gets(comment2);
-
- /* Output the data to the printer. */
-
- fprintf(printer, "\n%s", title);
- fprintf(printer, "\n%s %s", name, date);
- fprintf(printer, "\n%s", comment1);
- fprintf(printer, "\n%s\n", comment2);
-
- /* Flush the buffer and close the file pointer
- to the printer. */
-
- fflush(printer);
- fclose(printer);
- }
-
- All that was left was adding a loop to allow more than one label
- to be printed at a time.
-
- First, I decided that I would follow the current trend when
- updating software and add lots of "features." Actually, I
- realized that here was a simple program that could be used to
- demonstrate several things I often hear questions about:
-
-
-
-
-
- Issue C News 12
-
-
- - Checking the printer status, is the printer online?
-
- - Sending escape codes to the printer.
-
- - Clearing the screen.
-
- - Getting the system date.
-
- - An example for yorn(). (yorn() is a handy function
- for asking yes/no questions which Jaime Dasilva
- showed me a year or so ago.)
-
- The compiler used for the code in this program is Turbo C 2.0,
- but most functions should compile with little, if any,
- modification in any other MS-DOS compiler.
-
- (NOTE: Because not all readers of the C News use MS-DOS as their
- primary operating system, several of the following functions
- will not apply.)
-
-
- Sending output to the printer.
-
- Before going into the added "features," let's look briefly
- at how LABEL.C sends output to the printer, since this question
- comes up from time to time. Basically, just as printf() sends
- formatted output to stdout, fprintf() sends formatted output to
- a stream (normally stdprn). Both commands accept a series of
- arguments which are applied to a format specification contained
- in a format string:
-
- printf("\nHello world.");
-
- The difference is that in fprintf(), a stream must be specified:
-
- fprintf(printer,"\nHello world.");
-
- In this example the stream is the printer. Before we can send
- the formatted data to the stream, we must open the stream.
- Before we can open the stream, we need to declare it.
-
- Wait a minute, what's a stream? A stream is a file or
- piece of hardware which is manipulated as a pointer to a FILE
- object. To declare a stream, in this case the printer, we
- write:
-
- FILE *printer;
-
- In order to open the stream, we use fopen(), specifying the
- printer port as the filename and w as the mode:
-
- printer = fopen("LPT1", "w");
-
-
-
-
-
- Issue C News 13
-
-
- Once we have finished sending the data to the printer, we need
- to make sure that there is no data in the buffer, which we flush
- with fflush():
-
- fflush(printer);
-
- After flushing the buffer, we need to close the stream, which is
- done with fclose():
-
- fclose(printer);
-
- Admittedly, this is not the most detailed explanation of sending
- data to the printer, nor is it the only way to do so. However,
- this should give you enough background to understand how LABEL.C
- works and give you some points of reference for further study.
-
-
- Checking the status of the printer
-
- Since the people that will be using this program normally
- turn their printer on at the same time as they turn on their
- computer, since they share a surge protector, I was only
- interested in whether the printer was online or not.
-
- Without going into an in-depth discussion of DOS
- interrupts, checking the status of the printer can be done
- rather easily, by using BIOS interrupt 17, the printer-services
- interrupt, function 2. In C, we do this by using int86().
-
- Usually found in dos.h, int86() uses the following syntax:
-
- int int86(int int_number, union REGS *in_registers,
- union REGS *out_registers);
-
- and executes the specified software interrupt. Prior to
- executing the interrupt, the register values specified by
- *in_registers are copied into the registers. After executing,
- int86 copies the current register values into out_registers. It
- should be noted that in_registers and out_registers can point to
- the same structure, which is the case in the following example.
-
- In order to check status of the printer, we need to specify
- that we are using interrupt 17 (in hex), giving us:
-
- int int86(0x17, union REGS *in_registers,
- union REGS *out_registers);
-
- In order to specify function 2, we must first put 2 into
- register AH, which is accomplished by:
-
- regs.h.ah = 0x02;
-
-
-
-
-
-
- Issue C News 14
-
-
- Since we are interested in a printer attached to LPT1 (if you're
- not, I am), we need to put the printer number in DX:
-
- regs.h.dx = 0;
-
- (If you want to check the status of a printer on LPT2, the
- printer number would be 1.)
-
- After specifying both in_registers and out_registers to be
- of the structure specified by the REGS union, all that is left
- is to evaluate the returned value AH, returning 0 if the printer
- is not ready.
-
- The complete function is as follows:
-
- #include <dos.h>
-
- int prncheck(void)
- {
- union REGS regs; /* Declare regs to be of
- the structure union
- REGS. */
- regs.h.ah = 0x02; /* AH = 02 for printer
- status */
- regs.x.dx = 0; /* DX = 00 for LPT1 */
-
- int86(0x17, ®s, ®s);
-
- return(((regs.h.ah & 0x80) == 0x80) ? 1 : 0);
- }
-
-
- Sending escape codes to the printer
-
- After checking the status of the printer, sending escape
- codes to the printer is very easy. In fact, the hardest part is
- often finding the printer manual to look up the appropriate
- escape codes.
-
- For example, if we wanted to use elite printing on an ALPS
- P2000 printer, the escape codes necessary are 1B and 4D. In
- order to send them to the printer, all we need to do is declare
- them (in hex) as a character array
-
- char NLQ[] = {0x1B, 0x4D};
-
- and then send them to the printer
-
- fputs(NLQ, printer);
-
- That's all there is to it.
-
-
-
-
-
-
- Issue C News 15
-
-
- Clearing the Screen
-
- There are several ways to clear the screen, in fact, most C
- compilers have a function to clear the screen in one of their
- libraries. Assuming ANSI.SYS is present, we could send \xB1[2J
- to the screen to clear it. An easier way would be to send a
- series of carriage returns/linefeeds to the screen. All these
- methods will clear the screen, but what it we only want to clear
- a portion of the screen? By using the video BIOS scroll-window
- function, interrupt 10, function 6, we can use int86() to clear
- the screen or a portion of it. That's why rather than hard code
- a screen size into this function, I have chosen to have the
- values for the number of rows and columns in the screen to be
- passed to the function.
-
- Wait a minute . . . "scroll-window," isn't that the same as
- sending a series of carriage returns/linefeeds? Well, I admit
- it, it is very close. However, this screen clearing function
- can be used to clear just a portion of the screen, as it
- specifies the area to clear.
-
- AL contains the number of lines to scroll. If AL is equal
- to 0 or is greater than number of rows specified by DH, the
- screen is blanked.
-
- #include <dos.h>
-
- void clrscr(rows, columns)
- int rows, columns;
- {
- union REGS regs;
- regs.h.ah = 6;
- regs.h.al = 0; /* Number of lines to
- scroll. */
- regs.h.bh = 7; /* Attribute to use for the
- screen. */
- regs.h.ch = 0; /* Row, upper left corner. */
- regs.h.cl = 0; /* Column, upper left
- corner. */
- regs.h.dh = rows;
- regs.h.dl = columns;
-
- int86(0x10, ®s, ®s);
- }
-
- One problem with clearing the screen in this manner, is that the
- cursor is left at the lower right corner of the screen. Using
- the BIOS cursor-position function, interrupt 10, function 2, and
- int86(), we can specify the row in DH and the column in DL and
- reposition the cursor wherever we want it.
-
-
-
-
-
-
-
- Issue C News 16
-
-
- #include <dos.h>
-
- void set_cursor(rows, columns)
- int rows, columns;
- {
- union REGS regs;
-
- regs.h.ah = 0x02;
- regs.h.bh = 0;
- regs.h.dh = rows; /* Return cursor to this row. */
- regs.h.dl = columns; /* Return cursor to this column. */
-
- int86(0x10, ®s, ®s);
- }
-
- A faster, simpler way to clear the entire screen would be to use
- interrupt 10, function 0, the BIOS set video mode function. Of
- course, you must know the display mode value for your system,
- which goes in AL. For a 16 color EGA display adapter, connected
- to an EGA monitor, with a pixel resolution of 640 x 350, a
- character display of 80 x 25, the value for AL is 2.
-
- #include <dos.h>
-
- clrscr()
- {
- union REGS regs;
-
- regs.h.ah = 0;
- regs.h.al = 2; /* Display mode. */
- int86(0x10, ®s, ®s);
- }
-
-
- Getting the date
-
- Well, we've been using interrupts for everything else, so
- it should not be a surprise that we will use an interrupt to get
- the system date. DOS interrupt 21, function 2A, will return the
- date of the DOS internal clock. (NOTE: The DOS internal clock
- is the clock that can set by the operator with DATE and/or TIME
- in AUTOEXEC.BAT or at any DOS prompt.)
-
- In the previous functions where we have used the DOS
- interrupts, we have used int86(); but to get the system date, we
- will use intdos(). (We could use int86() just as easily.)
-
- While int86() is a general 8086 interrupt function,
- intdos() is a general DOS interrupt interface. Rather than have
- to specify interrupt 21, intdos() automatically accesses the DOS
- interrupt 21. Other than not having to specify the interrupt
- number, intdos() works just like int86().
-
-
-
-
-
- Issue C News 17
-
-
-
- The DOS interrupt 21 function to get the system date is 2A,
- so we have to set the value of AH to 2A.
-
- Unlike our previous functions, the system date will be
- returned in three registers, DH, DL, and CX. (If we wanted the
- day of the week, it would be returned as AL.) The numeric value
- for the month (1 through 12), is returned in DH. The day is
- returned in DL. The year, from 1980 to 2099 is returned as CX.
- In order to write these values to a string, we use sprintf().
- (Because we want the date in MM/DD/YY format, we need to
- subtract 1900 from the value in CX.)
-
- #include <dos.h>
-
- char *get_date()
- {
- static char date[9];
- union REGS regs;
-
- regs.h.ah= 0x2a;
- intdos(®s, ®s);
-
- sprintf(date, "%02.2d/%02.2d/%02.2d", regs.h.dh,
- regs.h.dl, regs.x.cx-1900);
-
- return(date);
- }
-
-
- Yes or no answers with a default: yorn()
-
- Okay, enough messing with interrupts. The need often
- arises for a program to ask a yes or no question. In many
- cases, it would be nice to have a default answer where the user
- just has to hit enter. There are a number of ways to do this,
- but my favorite is yorn(), which Jaime Dasilva posted on the C
- BBS about a year or so ago. It's not an earth shaking function,
- but it is the answer to an often asked question and it makes
- asking a number of such yes/no questions much easier.
-
- What makes yorn() nice to use is that the question and the
- default answer are passed to the function. So, while yorn() has
- expected lines
-
- if(c == 'Y' || c == 'y')
- return YES;
- else if(c == 'N' || c == 'n')
- return NO;
-
- you don't need to repeat them every time you have to ask a yes
- or no question which has a default answer. There is nothing
-
-
-
-
-
- Issue C News 18
-
-
- difficult about yorn(), as can be seen by the following code,it
- is fairly self-explanatory.
-
- /* yorn.c - yes/no prompting, with default. */
-
- #include <stdio.h>
- #include <string.h>
-
- #define YES 1
- #define NO 0
- #define LINELEN 129 /* DOS max line length + 1 */
-
- int yorn(char *prompt, int dfault)
- {
- char s[LINELEN], c;
- int len;
-
- printf("%s (%c) ", prompt, dfault ? 'Y' : 'N');
- fgets(s, LINELEN, stdin);
- len = strspn(s, " \t\n"); /* skip whitespace */
-
- if(len < strlen(s))
- {
- c = *(s + len);
- if(c == 'Y' || c == 'y') return YES;
- else if(c == 'N' || c == 'n') return NO;
- }
-
- return dfault;
- }
-
-
- BLOB.C
-
- The original C version of this label program (above), was
- named LABEL.C, why did I change it to BLOB.C? Because it kept
- growing and growing.
-
- The revised code for BLOB.C is included in the archive with
- this file. Most of the code should be self-explanatory by now.
-
- BLOB is not meant to be a tight, small label program.
- There are a lot of things that could be done differently. BLOB
- serves as an example of a few handy little functions, functions
- which answer some commonly asked questions.
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 19
-
-
- =================================================================
- Beginner's Column by Wayne Dernoncourt
- =================================================================
-
-
-
- This column is going to deal with structures, more
- specifically with data structures. In a building, a structure
- is an object composed of one or more parts with a common purpose
- of being a building. Different types of structures will have
- variations in the parts, but they all contain the same basic
- parts (i.e.. roof, walls, doors, windows, etc.). If you
- duplicate a structure, the new one will have the same pieces as
- the one that you duplicated. If you go into a modern apartment
- complex, most will have three or four floor plans for their
- various apartments. All apartments share components with other
- dwelling units, from townhouses to mansions, -- all have
- bathrooms, kitchens and bedrooms, etc. These components can be
- thought of as different types of data elements (ints, floats,
- chars, etc.). Just as one apartment building has multiple
- dwelling units, an apartment complex can have multiple apartment
- buildings. One of the data elements that a structure can
- contain is another structure (of course you can't have a
- circular reference).
-
- A data structure can be thought of in the same way.
- Different data structures are composed of different variables.
- The entire data structure is located in contiguous memory. If a
- data structure is composed of 2,000 bytes, those 2,000 bytes of
- memory will be located in one piece of memory. This is a
- requirement imposed by the ANSI standard. Unfortunately this
- usually has the side effect of imposing a restriction on IBM PC
- programs on the size of data structures. Data structures can be
- made up of integers, floats, characters or structures or arrays
- of any of these or any combinations of these.
-
- In a C program, there are two methods of accessing the data
- in a structure. This article will deal with the simpler of the
- two, while next issue's article will discuss the more advanced
- method.
-
- To illustrate this concept, consider the following
- requirement: You have to write a program that will read a series
- of files and perform the following editing functions:
-
- 1) Turn IBM special characters into blanks (printers don't
- usually handle these characters very well)
- 2) Drop trailing blanks from lines (sometimes the actions from
- the first step will result in a line of nothing but blanks
- 3) Print the resulting line to a file
-
-
-
-
-
-
-
- Issue C News 20
-
-
- Given these requirements, let's write an algorithm to solve this
- problem.
-
- 1. GET information about filetypes that we're interested in
- 2. OPEN output file - check for success
- 3. AS long as the request for info on good filetypes is filled:
- 3.1 OPEN the file for reading - check for success
- 3.2 WHILE not at EOF
- 3.2.1 RESET the input buffer
- 3.2.2 READ from the file into the input buffer
- 3.2.2.1 CHECK for special character and
- translate if needed
- 3.2.3 TRIM the line of trailing blanks
- 3.2.4 PRINT the line to the output file
- 3.3 GET info on the next file for reading
- 3.4 CLOSE the current input
- 4. CLOSE the output file
- 5. END the program
-
- Translating this algorithm into a program, here is the actual
- code that is used:
-
- /*
- This program is supposed to read all files with a filetype of
- TST, convert all of the non-standard ASCII characters (all
- characters not in the range of \x20 to \x7f to a space, all
- trailing blanks are then to be eliminated with the resulting
- line written to an output file.
- */
-
- /* prototypes go here */
- int read_line (char *in_line);
- void trim_line (char *in_line, int length);
-
- /* include files go here */
- #include <stdio.h>
- #include <dos.h>
- #include <dir.h>
-
- /* Global variable declarations go here */
- FILE *infile, *outfile; /* For some reason,
- I have better luck
- with files as global
- variables. */
- main()
- {
- /* Local variable declarations */
- char in_line[150];
- int length;
- int found_file;
- struct ffblk fileinfo; /* This declares a STRUCT */
-
-
-
-
-
-
- Issue C News 21
-
-
- /* find the first file to read */
- found_file = findfirst ("*.tst", &fileinfo, 0); /* 1. */
-
- /* open the output file */
- if ((outfile = fopen("test.out","wt")) == NULL) /* 2. */
- {
- printf ("I can\'t open the output file\n");
- return(0);
- }
-
- /* while files are present to process */
- while (!found_file) /* 3. */
- {
- /* 3.1 */
- if ((infile = fopen(fileinfo.ff_name,"rt")) == NULL)
- {
- printf ("I can\'t open the input file\n");
- return(0);
- }
-
- while (!feof(infile)) /* 3.2 */
- {
- memset(in_line, ' ', 150); /* 3.2.1 */
-
- length = read_line(&in_line[0]); /* 3.2.2 */
-
- trim_line(&in_line[0], length); /* 3.2.3 */
-
- fprintf (outfile, "%s\n", in_line); /* 3.2.4 */
- }
- found_file = findnext(&fileinfo); /* 3.3 */
- fclose(infile); /* 3.4 */
- }
- fclose(outfile); /* 4. */
- } /* 5. */
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 22
-
-
- int read_line(char *in_line)
- /*
- This function returns the line read in from the input file.
- Modify the input character string so that all fall into the
- range of printable ASCII characters. The only character
- excluded is the new-line character. All non-conforming
- characters are translated into blanks.
- */
- {
- char unsigned in_char='\x00';
- int index = 0; /* index is the character
- position in the return buffer,
- it's the length of the buffer */
-
- while (in_char != '\n' && !feof(infile))
- {
- fscanf(infile, "%c", &in_char);
-
- if ((in_char < ' ' || in_char > '\x7F') && in_char != '\n')
- {
- in_char = ' '; /* 3.2.2.1 */
- }
- in_line[index] = in_char;
- index++;
- }
- index--;
- in_line[index] = ' ';
-
- return(index);
- }
-
- void trim_line(char *in_line, int length)
- /*
- This functions returns a line trimmed of all trailing blanks
- */
- {
- int index;
- for (index = length; in_line[index] == ' ' && index >= 0; index--)
- {
- in_line[index] = '\x00';
- }
- }
-
- In previous articles, you've already been introduced to
- using files. Whenever you open a file, the system fills a
- structure with data regarding this file. The FILE macro
- (defined as part of the stdio.h header) creates this data
- structure. Another data structure is created by the use of
- struct keyword, in this case the type is called ffblk and I
- called the data structure instance fileinfo. The template for
- the ffblk structure is found in the dir.h header file.
-
-
-
-
-
-
- Issue C News 23
-
-
- I initially fill the fileinfo data structure with
- information using the function findfirst (see line 1). This
- function returns a zero if no files were found that matches the
- search criteria (in this case all files with a file type of
- TST), otherwise it returns a number (what the number is doesn't
- matter). Notice that the data structure is passed to the
- function with the '&', this instructs the compiler to pass the
- address of the structure to the function. I assign the value
- returned by findfirst to a variable called found_file. I update
- the fileinfo data structure on other files using the findnext
- function.
-
- As long as found_file is not zero (see line 3), I open the
- file that was found by using the ff_name offset of the data
- structure. This could be confusing to some people, let me stop
- and try to explain this a little more. The fileinfo data
- structure is composed (in this instance) of a 21 character array
- reserved for DOS, a 1 byte character that is the file attribute
- (i.e., read-only, hidden, system, etc.), 2 unsigned integers
- that contain the date and time fields, a long integer that
- contains the length of the file and a null-terminated character
- array containing the file name. When the program is run, this
- data structure initially contains undefined data. This data
- structure changes to reflect data on the files that we're
- interested in. This data is updated by using the findfirst and
- findnext functions. The findfirst function fills out the data
- structure initially and the findnext function gets information
- on later entries. (see line 3.3)
-
- Next month, another way of accessing data structures.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 24
-
-
- =================================================================
- Where's That Number? by Jim Singleton
- =================================================================
-
-
- A Project In Programming Design (Revisited)
-
- Last issue, we looked at one of the textbook methods of
- programming design. While the seven steps involved were covered
- in order and in sufficient depth to understand the processes
- involved, I have to apologize for the article. Due to a variety
- of reasons, most notably that I was leaving the country the day
- the article was due, the code accompanying the article was not
- as good as it should have been. As published, PHONENUM.C will
- work. While I have a variation of PHONENUM.C, I felt it needed
- to be modified slightly for general use. At the same time,
- there were things which I didn't change, which I should have
- changed.
-
- Looking back at PHONENUM.C, what's wrong with the code? As
- you may remember, I mentioned one bug in the article, which is
- was using ASCIIZ strings with no initialization. (If you missed
- this one and found others, you're not alone.) This causes
- garbage characters in the database, which results in different
- output files every time you add names to the database. This
- makes it virtually impossible to use a comparison of the
- database as a means of testing variations to the program.
-
- A second glaring error, which I didn't notice until,
- Charles Falconer pointed it out, was the use of fixed fields.
- As Charles correctly pointed out, this can "lead easily to nasty
- bugs, such as the use of 'gets' in [the] program and the
- associated C insecurities." (Luckily, Charles, I have not yet
- been bitten by this bug.) In addition, in the case of the field
- for the phone number, it doesn't allow for extensions, overseas
- numbers, etc. (As one can tell, I have never put my fiancee's
- phone number, in Ireland, into the program.)
-
- Are there other errors? Yes and no. As I have mentioned,
- the program will work and does do what it was designed to do.
- In fact, since this seems as if it is becoming an ongoing series
- of articles, we can easily make modifications to the code with
- each installment. However:
-
- - I overlooked the fact that the program requires the
- user to correctly enter the exact name of the person
- whose phone number they are retrieving.
-
- - I also did not allow any means for checking to see
- what numbers are already in the database. (Although
- this was considered for a later article, it is a feature
- that should be present at the outset.)
-
-
-
-
-
- Issue C News 25
-
-
-
- - I never did consider the size of the program, which
- is rather large for such a limited number of features.
- (Charles said this best, as "the whole thing seems to
- be squashing mosquitos with a pile driver.")
-
- I received a number of proposed modifications to
- PHONENUM.C, ranging from several lines to completely new
- programs. Charles Falconer did not care for the interior design
- of PHONENUM.C, so he rewrote PHONENUM.C, using a more modular
- approach. While I have seen this approach before, I appreciate
- it much more after taking a crticial look at my code from issue
- 18. Charles' formatting and break-down philosophy results in
- self-documenting code, with modules which are small and of a
- single purpose. Charles' version of PHONENUM is included in
- this archive in the file FONENUM.C. Thanks, Charles.
-
- What's next? The obvious shortcomings of the program are
- listed above, so anyone that wants to improve PHONENUM.C can
- either use them as a guide or look at Charles' program.
- PHONENUM.C is a simple program, so it doesn't really lend itself
- to some of the "features" discussed in the last issue; however,
- it will probably appear from time to time as a platform for
- demonstrating different functions.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 26
-
-
- =================================================================
- Portability Coding Issues
- =================================================================
-
-
-
- When I first started working in an environment where I was
- using multiple C compilers I assumed that given the ANSI C
- standard, writing C code that was easily portable between the
- compilers would present little or no difficulties. My favorite
- environment to develop code in is Turbo C. I thought that I
- could tweak all the ANSI C flags on the TC compiler, write the
- routines, test them with some drivers and then move the source
- to the target systems and everything would be fine. This idea
- turned out to be naive more often than not. After a few trials
- it became obvious that ANSI C by one compiler's definition ain't
- necessarily ANSI C by another's. Plus, it turns out that there
- are a lot of things that the ANSI C standard does not mandate
- but leaves up to the implementation. To avoid the situation
- where I would be maintaining multiple versions of the same
- source file, I needed some guidelines that would allow me to
- write more portable code.
-
- For my purposes I defined 'portable C code' as code that
- can be compiled and run on multiple operating systems and
- hardware platforms, with no source modifications, and produce
- identical results (or at least acceptably similar, taking into
- account different data representations). This would seem to be
- an obvious blanket definition but I thought that I had better
- give myself an ideal situation to shoot for.
-
- Exceptions would be (there are always exceptions):
-
- 1) Low level routines that can be non-portable because of
- unavoidable machine dependence. (i.e. mapping of
- hardware or operating system data structures)
-
- 2) Major differences in compiler implementations.
-
- In the case of machine dependent routines, I decided that I
- could isolate these into Machine Dependent Libraries. In the
- case of multiple compilers I could stick with the lowest common
- denominator to eliminate annoying 'minimal' code changes.
-
- My approach was to identify native C operations and common
- coding assumptions that could produce non-portable code,
- regardless of compiler adherence to the ANSI C standard. These
- are listed in this article. There are complete volumes written
- upon portability and the C language and I make no claim that
- these guidelines cover all aspects of portability. They do
- however provide good 'rules of thumb' and I have found them
- useful in minimizing my portability problems. I used a number
-
-
-
-
-
- Issue C News 27
-
-
- of reference books while compiling this list and I can recommend
- the following for further reading:
-
- o C:A Reference Manual Second Edition, Samuel P. Harbison
- and Guy L. Steele, Tartan Laboratories, Prentice-Hall
- Software Series 1987
-
- o Portability and the C language, Rex Jaeschke, Hayden
- Books - C Library 1988
-
- o The Waite Group's Essential Guide to ANSI C, Naba
- Barkakati, Howard W. Sams & Company 1988
-
- If you are reading this you are assumed to have a working
- knowledge of C, its data types and constructs. This document
- does contains some discussion of binary and unary conversions,
- trigraphs and character escape sequences. When applicable,
- acceptable alternatives to the operations discussed are
- specified. A limited explanation is usually given to avoid
- making arbitrary do or don't statements.
-
- ANSI C is referenced where appropriate and when the
- operation involves ANSI C extensions. However, if you are using
- multiple compilers, refer to their specific documentation to
- determine what is acceptable to all of them. If that happens to
- be an ANSI C construct, great!!
-
- For reference, the systems that I have been working with
- are:
-
- 1. IBM PC/RT running AIX 2.2.1
- 2. IBM 4381 running VM/XA SP2 using C/370
- 3. DEC VAX/VMS
- 4. PS/2 60 with DOS 3.3 and TURBOC 2.0
-
-
- Bit Fields
-
- Due to differences in byte ordering, bit field widths and
- alignment restrictions on different machines, code using bit
- fields will likely be non-portable. Use of bit-fields should be
- restricted to to situations where hardware defined data areas
- must be matched exactly.
-
- C specifies that no compiler has to allow bit fields of any
- type except unsigned, but some compilers do allow signed (that
- is sign extension occurs when extracting the contents). Use of
- any type other than unsigned for bit fields is considered less
- portable than using bit fields at all.
-
-
-
-
-
-
-
-
- Issue C News 28
-
-
-
- Bit Wise operations
-
- Due to different implementations of signed integer numbers,
- the bitwise operators: ^, |, and ~ should NOT be used on signed
- values. Likewise the shift operators >> and << should NOT be
- used on signed operands.
-
- ANSI C mandates that integers use binary encoding to permit
- portable bitwise operations and shifts upon POSITIVE integers.
- If the contents of an integer could become negative, bitwise
- operations should not be used as results will be unpredictable
- when ported. Casts may be used to cast operands to be
- unsigned.
-
-
- Byte Order and Alignment
-
- Routines coded that assume a particular byte order will not
- be portable. Likewise, routines that assume specific data
- alignment will not be portable.
-
- Addressing may be right-to-left or left-to-right.
- Alignment restriction may not exist, may be strictly enforced or
- in some cases adjustable by the hardware or implementation
- depending upon the data type referenced. Run time errors or
- unpredictable results may occur if addressing and alignment
- conditions are assumed.
-
-
- Numeric Escape Codes
-
- Numeric escape codes should not be used for two reasons.
- They tend to hide the meaning of the code in a cryptic mass of
- numbers and they are dependent upon the implementation's
- character set. If the specific encoding is not present in the
- character set, results will be unpredictable. Also there is an
- implicit assumption that characters will be represented in eight
- bits. This is not portable either. Escape codes should be hid
- in MACRO definitions both for code clarity and isolation.
-
-
- Character Constants
-
- Character constants are written by enclosing a character in
- apostrophes and have type 'int'. Most computers contain
- integers in a storage area large enough to contain several
- characters and thus some C implementations allow multi-character
- constants such as 'ABC' creating an integer value (not a string,
- no '\0' ending character). There are implicit assumptions about
- byte-ordering involved in the use of such a constant, so the
- actual value is non-portable.
-
-
-
-
-
- Issue C News 29
-
-
-
- ANSI C allows multiple character constants but their actual
- value is left up to the implementation. Note that
- multi-character constants are not the same as multi-byte
- characters.
-
- (See previous discussion on byte ordering)
-
-
- Character Definitions
-
- All character definitions should be defined as 'unsigned'
- for consistency and portability. Different implementation may
- have default characters as signed or unsigned or even
- pseudo-unsigned (treated as signed when performing the usual
- unary conversions but the actual value cannot be negative). If
- left as an implicit definition, unpredictable results could
- occur.
-
-
- Character Escape codes
-
- Some character escape codes are defined to be independent
- of the computers character set. The appear in code preceded by
- a back slash. (e.g.'/n'). The character escape codes that are
- allowed by the ANSI standard are listed here:
-
- a produce an audible alert (ANSI extension)
- b backspace
- f form feed
- n newline
- r carriage return
- t horizontal tab
- v vertical tabulate
- \ backslash
- ' single quote
- " double quote
- ? question mark
- <octal digits> Interpretation depends upon printer or terminal
- x<hex digits> Interpretation depends upon printer or terminal
-
- Some compilers may or may not support all of the above
- sequences. Check the compiler documentation.
-
-
- Character Sets
-
- ANSI C introduces trigraphs so that C programs may be
- written in a subset of ASCII. For example the character
- trigraph ??) will represent the ASCII character ].
-
-
-
-
-
-
-
- Issue C News 30
-
-
-
- I personally find that trigraphs are a pain to use and they
- make for really ugly code. However when porting C source to a
- machine which does NOT support certain ASCII characters the
- trigraphs must be used. The port procedure must be responsible
- for converting the necessary ASCII characters to their trigraph
- equivalent. For example, EBCDIC machines do not support the
- characters [ and ]. If the C source is coded on an ASCII
- machine and ported to an EBCDIC machine, the characters [ and ]
- must be translated to their trigraph equivalents ??( and ??)
- respectively.
-
- If the target systems compiler does not support trigraphs
- or the required characters, MACROs should be defined for the
- appropriate escape sequences. I have seen this done
- successfully in the old ORACLE C compiler for IBM 370 machines
- before C/370 blotted that landscape.
-
- The translation of trigraphs in the source program occurs
- before lexical analysis (tokenization) and even before the
- recognition of character escapes introduced with a backslash \.
- Only these exact nine trigraphs are recognized.
-
- Trigraph ASCII Character
- -------- ---------------
- ??( [
- ??< {
- ??/ \
- ??' ^
- ??= #
- ??) ]
- ??> }
- ??! |
- ??- ~
-
-
- Comments
-
- Comments are defined as beginning with /* and terminating
- with */. Nested comments are NOT ANSI standard although some
- compiler implementations do allow it. If a section of code is
- to be suppressed and the section contains comments, preprocessor
- statements should be used:
-
- #if 0
- ..........
- ..........
- #endif
-
-
-
-
-
-
-
-
-
- Issue C News 31
-
-
-
- rather than:
-
- /*
- .........
- .........
- */
-
-
- Data Type Sizes
-
- The exact size of the various data types for an
- implementation is usually defined in the limits.h and float.h
- header files. This is ANSI C and most other compilers follow it
- although other functions and MACROs may also be present. Check
- the individual compilers files before making any assumptions as
- to the size of a data type.
-
- See discussions of floating point and integer types.
-
-
- External names and internal identifiers
-
- The C language allows and is sensitive to mixed casing in
- identifiers. Early versions of C specified 8 significant
- characters in identifier names. ANSI C requires implementations
- to allow 31 significant characters and some allow more. Again,
- use the lowest common denominator if using multiple compilers.
-
- Although C permits long external identifiers, the host or
- target operating system may require shorter names. All external
- name should be encapsulated through the use of pre-processor
- statements. This allows meaningful names to be coded and
- permits maximum portability.
-
- #define tut_error_handler tut00u
-
- extern void tut_error_handler();
- int *p;
-
- if (!p) tut_error_handler("Null pointer error");
-
-
- Floating Point types
-
- There are no requirements in C implementations about the
- relative sizes of the floating-point and integer or pointer
- types. Floating point number representation is completely
- machine dependent. It is generally assumed that the type
- 'double' will be large enough to accurately contain all value of
- type 'long'. While this is likely to be true, C does not
- require it and any code written should avoid depending on this
-
-
-
-
-
- Issue C News 32
-
-
- assumption.
-
- The 'long double' type give C program access to an extended
- precision floating point values. However, implementation are
- free to make 'long double' the same size as 'double' as they are
- free to make 'double' and 'float' the same. Check the
- individual compiler documentation before making any assumptions
- on floating point sizes.
-
- ANSI C allows floating arithmetic to be done without
- 'widening' of the operands.
-
-
- Function Pointers
-
- Function pointers must be explicitly typed or the results
- can be unpredictable. Implementations can use different sizes
- for data and function pointers. Assuming the default 'int'
- return type is 'good enough' is not good enough.(See discussion
- of pointers)
-
-
- Input and Output
-
- All input and output (I/O) in C programs should be done
- using C's standard I/O facilities. These are based upon the
- concept of a stream which may be a file or a device. A file
- pointer is returned to the application from the function fopen
- and is used as an argument to most of the I/O facilities. Calls
- to host operating system utilities to perform I/O are not
- allowed (or portable).
-
-
- Integer Arithmetic
-
- There is not much that can be done about predicting run
- time divide by zero other than to check for a 0 divisor at every
- computation (which may incurr unacceptable overhead). It should
- be noted here that the results of an overflow of a signed
- integer type are unpredictable. An incorrect value may be
- produced, the program may terminate execution or some
- machine-dependent trap or exception may occur. This holds for
- >> or << operations whose right hand operand is too large or
- negative as well.
-
- Unsigned integer overflow results are well defined by C,
- namely, the result is computed using modular arithmetic, but
- this is dependent on the representation of int. Routines should
- never be coded to take advantage of any action occurring in the
- case of a signed overflow and dependenc on the modular nature of
- unsigned overflow should be avoided.
-
-
-
-
-
-
- Issue C News 33
-
-
- Integer Types
-
- Integers come in three types: short, int and long. Int may
- not be shorter than short and long may not be shorter than int.
- However it is permitted for short and int to be the same size or
- for int and long to be the same size. Of the three, int is the
- default integer type and thus is likely to be the most efficient
- in a given implementation. Unfortunately it is also the least
- portable being implemented in 32 bits by some compilers and 16
- on others. A long type integer is likely to be implemented in
- 32 bits as it can give the largest range of integer values.
- Operations on type long may be slower than operation on type
- int.
-
- The choice of what integer type to use comes down to
- portability or efficiency.
-
-
- Initializers
-
- 'K & R' C did not allow initialization of automatic
- aggregates (arrays). ANSI C does. I have found that if a
- compiler does not follow a complete ANSI C implementation, this
- is not likely to be supported. Check the appropriate compiler
- documentation.
-
-
- MACROs
-
- Substitution of macro parameters into string constants and
- character constants is up to the implementation of the
- compiler. For example the definition:
-
- #define MAKESTRING(x) "x"
-
- used in the following statement:
-
- MAKESTRING( a += 1 /* Comment */)
-
- could result any one of the following:
-
- "a += 1 /* Comment */"
- "a += 1 "
- "a += 1 /**/"
- "a+=1/* Comment */"
- "a+=1"
-
- ANSI C does describe the # and ## operators to be used for
- 'stringization' and 'token merging' however check with the
- appropriate compiler documentation to see what is supported and
- be sure sure you know what you are trying to achieve.
-
-
-
-
-
-
- Issue C News 34
-
-
- Pointers
-
- Pointers should be initialized to null or to their desired
- run time value when they are declared.
-
- int foo;
- int *p = NULL;
- int *q = &foo;
-
-
- Some implementation will give compile errors if a pointer
- is not initialized before use, other will go ahead and use
- whatever is in the pointer. Defining a pointer to null should
- force some sort of run time "null pointer assignment message" if
- the pointer has not been properly defined prior to use.
-
- Assigning integers to pointers should not be done except in
- the special case of assigning a constant zero to initialize a
- null pointer. Note that the null pointer concept does not
- necessarily mean an all-bits-zero value.
-
- Proper type casts must be used when assigning pointers to
- pointers of different types. This will guarantee portability
- and conversion without error.
-
- long number;
-
- long *lng_ptr = &number;
- char *string;
- .........
- .........
- string = (char*)lng_ptr;
- .........
- .........
-
-
- Register Variables
-
- You should not use the unary operator '&' upon a register
- variable. Some implementations may support this as register is
- only a hint to the compiler and not a mandatory requirement, as
- well as the fact that on some computers, registers are
- addressable as if they were storage locations. On the other
- hand if a register is available and used, the & operator would
- force it to be auto instead defeating the whole purpose of the
- register declaration. Some compilers will issue warning
- messages but this should not be counted upon.
-
-
-
-
-
-
-
-
-
-
- Issue C News 35
-
-
-
- Program return codes
-
- Do NOT rely upon the return code of a program being that
- which is specified in the return statement. Use the exit
- library function instead.
-
- ANSI C does mandate that an explicitly returned value from
- main will be the programs' exit code.
-
-
- Switch Statements
-
- Do NOT rely on a switches case being resolved in the order
- they are specified. The order of case testing is undefined and
- depending upon the set of case values, and their contiguity, the
- implementation may test in a variety of ways, even within the
- same switch.
-
-
- Unions
-
- The only time a component of a union may be addressed is if
- the last assignment to that union was through the same
- component. It is not portable to assign one union component and
- then reference another. Some compilers will allow this, others
- will not compile or give an run time failure.
-
- union U { long c; double d; } x;
- long l;
-
- x.d = 1.0e10;
- l = x.c; /* not portable */
-
-
- Usual unary and binary conversion performed on operands
-
- Unary Conversions: applied to ^, | ,~ , <<, >> and function
- arguments:
-
- Original operand type Converted Type
- --------------------- --------------
- char, short int
- unsigned char unsigned
- unsigned short unsigned
- float double
- "array of T" pointer to T
- "function returning T" pointer to function returning T"
-
- Binary Conversions are done before Binary or Ternary Operations
- are performed. An operator that performs the usual binary
- conversions on its two operands, first performs the usual unary
-
-
-
-
-
- Issue C News 36
-
-
- conversions on each of the operands independently. The usual
- binary conversion as defined by ANSI C are:
-
- 1. If either operand is not of arithmetic type, or if the
- operand are the same type, no conversion are performed.
-
- 2. Otherwise, if one is of type long double then the other is
- converted to type long double.
-
- 3. Otherwise, if one is of type double then the other is
- converted to type double.
-
- 4. Otherwise if one operand is type float the other is
- converted to type float.
-
- 5. Otherwise, if one is of type unsigned long int then the
- other is converted to unsigned long int.
-
- 6. Otherwise, if one operand is of type long int and the other
- is of type unsigned int, and a long int can contain all unsigned
- int values, the unsigned int is converted to long int otherwise
- both operands are converted to unsigned long int.
-
- 7. Otherwise, if one operand is of type long int the other
- (which must now be type int) is converted to type long int.
-
- 8. Otherwise, if one operand is of type unsigned int then the
- other is converted to type unsigned int.
-
- 9. Otherwise, both operands are of type int and no other
- conversions are performed.
-
- These are similar to those defined by K&R except for expansion
- for long double and unsigned long.
-
- Some compilers convert type float in function argument lists to
- type double and some will supply an option to suppress this
- conversion. Check the compiler documentation.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 37
-
-
- =================================================================
- New PD/Shareware Releases by Barry Lynch
- =================================================================
-
-
-
- Listed below are some of the new programming related
- shareware or public domain utilities, libraries and code
- fragments that have been released over the last few months.
- Opinions expressed are of the author only. The files listed
- below are available from the Bulletin Board Systems that are C
- News Distribution points.
-
-
- Filename: MEXT17.ZIP
-
- The Microsoft Editor comes free with the C compiler and the
- MASM assembler. One of the capabilities of the editor is the
- ability of the programmer to write editor extensions in C. This
- file is a collection of extensions written by Fridtjof Weigel.
- The one limitation of this collection is that they were compiled
- with OS/2 extensions.
-
- Therefore, if you want to use them with the DOS based
- Microsoft Editor you are out of luck, unless you modify the
- source that is distributed. Listed below are some of the
- capabilities that are available with this extension library.
-
- - funclist: Builds a list of functions
- - keymacdef: Begins a key macro
- - keymac: Executes a keystroke macro
- - indent: Indent a range of lines
- - reflow: Wordwraps a paragraph
-
-
- Filename: C_MENUS1.LZH
-
- This file contains a menuing system written in TurboC v2.0
- by Karl Keyte of West Germany. A library of functions, header
- file and a reference file are included in the archive. The
- library contains functions to define a menu (define_menu),
- display (display_menu), remove (remove_menu) and various
- others. A sample program outlining the usage of the functions
- is not included in the archive. However, Karl will try to
- assist if you are willing to call him or send him e-mail or a
- letter. Karl states in the documentation that the source may be
- available depending upon whether the source is undergoing major
- modifications or not.
-
-
-
-
-
-
-
-
-
- Issue C News 38
-
-
-
- Filename: MABBRE.COM
-
- This archive is another set of extensions for the Microsoft
- Editor. These extensions implement templates for various C
- language keywords. For example: If you type in "w", and press
- Alt-tab (access the extension) the result will be "while ()".
- Setting up CABBRE (C language vs. PABBRE - Pascal also included
- in the above archive) involves copying the CABBRE.MXT file to
- the same directory where "Tools.ini" resides, and adding the
- following line to the "Tools.ini" file. "Load::CABBREV.MXT".
- The extension works as advertised and the source is included
- with the archive.
-
-
- Filename: STABV1.COM
-
- This is another extension for the Microsoft editor. Stab
- stands for "Smart Tab". The smart tab has two features:
- awareness of the insert mode, and the ability to to set variable
- spaced tabs. To load STAB, add the following line to your
- "Tools.ini" file. "Load::STAB.MXT". The source is also
- included in this archive.
-
-
- Filename: MCURFI.COM
-
- And finally, another Microsoft Editor extension. This one
- reconfigures the cursor. This is especially helpful when using
- the M editor in the 43 line mode. As with the other extensions
- mentioned previously, the source code is included in the
- archive.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 39
-
-
- =================================================================
- Article Submission Standards
- =================================================================
-
-
-
- All articles, reviews and letters to editor should be
- submitted as ASCII files. Please do not format the text in any
- way (no hyphenation, justification, indentation, etc.) since we
- use Proff to format C News. Proff takes care of the
- justification, footnotes and headers.
-
- You can send in your article on a diskette or send it
- electronically to one of the editors. See "How to Contact us
- here at C News" for more information.
-
- Barry
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issue C News 40
-
-
- =================================================================
- How to get hold of us here at C
- =================================================================
-
-
- You can reach us via Snailmail at:
-
- The C News
- P.O. Box 15314
- Arlington, VA 22215
- USA
-
- and electronically via the following electronic mail addresses:
-
- (Jim)
- FidoNet: 109/138.1
- CIS: 71540,2677
-
- (Barry)
- Fidonet: 1:124/3116
- North Texas C Programmers Board: 1-214-442-0223
- MCI Mail: 272-8067
-
- (Dan)
- Internet: dbk@cs.umd.edu
- UUCP: ...!uunet!mimsy!dbk
-
- (Rob Koel)
- European C News Distribution Point: 011-3185642891
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-