Dec 142017
C programmers newsletter issue #16.
File CNEWS016.ZIP from The Programmer’s Corner in
Category C Source Code
C programmers newsletter issue #16.
File Name File Size Zip Size Zip Type
CNEWS016.DOC 59747 17951 deflated
SETS.ZIP 47882 46423 deflated

Download File CNEWS016.ZIP Here

Contents of the CNEWS016.DOC file

Issue 16 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: Messages from the Editor ...................... 2

BOOK REVIEW: by Arnie Cherdak .......................... 3

COPYRIGHT-IT: Product Review by Jim Singleton ........... 5

BEGINNERS CORNER: By Wayne Dernoncourt ................. 8

SETS IN C (V1.0) by Arnold Cherdak ....................... 12

ARTICLE SUBMISSION STANDARDS ......................... 25

HOW TO GET HOLD OF US HERE AT CNEWS........................ 26

"C News" is an Electronic Journal published by the C BBS in
Burke, VA on a monthly basis. The subject for 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, or 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. To do so is in direct violation of the C News
License agreement. Copies of which are available from the C
BBS. This publication is Copyrighted under U.S. Copyright

Issue 16 C News 2

THE HEAP: Messages from the Editor


A couple of weeks ago we published Issue 15 of C News after
a long vacation. A few days later at the monthly C BBS user
meeting we discussed the future of C News. With the addition of
Dan Kozak and Jim Singleton to the staff here, we felt that C
News could continue and would grow. Dan has done an excellent
job of putting some macros together for PROFF and has put this
issue together. Jim Singleton reviewed the issue and provided
one of the articles. With this level of support I look forward
to the rest of this second year of publication.


Well the mailman has been dropping off more postcards from
around the globe these last couple of weeks. Postcards have
found there way here from Finland, Abu Dubai, Iowa, and
California. Keep up the good work and keep those cards


Once again the subject of CASE has crossed my desk. I just
finished a class in Systems Analysis and Design and was
impressed with some of the PC Based CASE tools that are
available. When you look at the price tag though of some of the
packages ($1500 in some cases) you realize that the only way you
will get a chance to use one is to get the boss to by it! Yeah
right you say..

Over the next year or so I am going to be working on a
small private project that is a combination of a SCCS system and
a CASE tool. As my thoughts on the mythical project are
finalized I will publish a series of articles here in C News. I
would like to generate some conversation this subject here in C
News and on the C BBS. If you have some thoughts on CASE and
would like some editorial space, send me a note in Snail Mail,
MCI Mail, Fido Mail or call the C BBS at 703-644-6478. I would
be very interested in hearing how some of you are making out
with the various CASE tools that are currently available.

Look forward to hearing from you, and now let's get on with
the 16th issue of C News.


Issue 16 C News 3

BOOK REVIEW: by Arnie Cherdak

The Waite Group's Essential Guide to ANSI C
by Naba Barkakati

Pub: Howard W. Sams & Co., Indianapolis, IN, 1988


I've spent a lot of money on books about computer languages
and programming but this inexpensive little gem is just about
the best bargain I've come across yet. The author claims that
it's not for the neophyte. In the author's words, it's for
"intermediate to professional level programmers." It's a
reference guide that summarizes the basic features of the ANSI C
standard (1988) including the preprocessor, new language
features as compared with the original K&R default standard, and
standard library functions. It also provides individual
reference entries for each standard library routine along with
examples of their use. All this and two quick reference guides
for the library routines as well as a fairly sizable index make
this book easy to use.

This book is not organized for learning C. That's why it's
not supposed to be for the beginner if this is the only source
he or she would have to use. However, in conjunction with other
sources of instruction and a good ANSI C compiler, say, Turbo C
version 2.0 (which is almost an ANSI C compiler), this will make
a dynamite reference. The Turbo C 2.0 manuals have most of this
information but the reader needs to wade through two volumes
full of all kinds of stuff to get at the nuggets needed to use
the language's basic features. This reference guide has only
the nuggets and a few clearly written descriptions of basic
stuff such as one of the most succinct and understandable
descriptions of memory allocation procedures I've ever run
across. It has excellent descriptions of other subjects as well
in the introductions to the other 9 chapters describing the
various groups of library functions.

After several months of using this book, I find the
reference guides for library functions to be invaluable. There
are other books like this but none I've seen have similar
indexes to the library functions and, hence, are of dubious
value by comparison.

Also, in using the function descriptions and function
parameter descriptions with Turbo C version 2.0, I've found
complete agreement, so far, which means I can use this guide

Issue 16 C News 4

which is much simpler in most respects than the Turbo Reference

The Waite Group also offers similar guides to Microsoft C
(ver 5.1) and Turbo C (ver 1.0, 1.5, and 2.0 in one volume) that
cover similar ground including the extensions offered by each
compiler. These are only a dollar more. I opted for the plain
vanilla ANSI standard book so that I could easily determine what
features are in the standard and not part of the compiler's
enhancements. It makes writing portable code that much easier.

Issue 16 C News 5

COPYRIGHT-IT: Product Review by Jim Singleton

Product: COPYRIGHT-IT, version 1.0809
Cost: $25.00
Manufacturer: Synthetic Intelligence Inc.
286 Fifth Avenue, Suite 707
New York, NY 10001

If you ask a half dozen programmers, of varying experience,
how to copyright a program, the chances are pretty good that
you'll get a half dozen different answers. One way which just
about everyone agrees is correct is to file for a copyright with
the United States Copyright Office. Unfortunately, many people
think that this is difficult. Unlike a patent, which requires
quite a bit of work (and usually an attorney), filing the
paperwork for a copyright is not too difficult. COPYRIGHT-IT,
from Synthetic Intelligence Inc., makes the process even

To file for a copyright, one must fill out Form TX, which
can be obtained from the United States Copyright Office.
COPYRIGHT-IT guides an author through the completion of Form
TX. (It should be pointed out that Form TX and COPYRIGHT-IT are
not just for software, but for any material which can be
copyrighted.) Two blank copies of Form TX are included with the
package and additional copies of Form TX may be obtained by
calling the Copyright Office (202-287-9100).

Opening the package reveals a sheet of instructions, two
blank copies of Form TX, a sample of a completed Form TX, and
the program disk. (The program has no color or graphics, so it
should run on any monitor/video card combination.) The one page
instructions are clear and concise, and these instructions are
also included on the disk. One might be tempted to just glance
at the sample copy of Form TX and just get started with the
program, but it does contain a very useful piece of
information. The sample copy shows how to correctly align the
form for printing. This is covered in the instructions, but it
is helpful to see where the alignment dots should appear on the
form. (While the alignment dots are printed on the form, they
do not deface the form and are hardly noticeable.)

COPYRIGHT-IT starts out by displaying the copyright notice
and the warranty information. These are pretty standard and the
disk is warranted free from defects, etc. for 90 days.

The next two screens describe the program and the copyright
process. COPYRIGHT-IT is described as a tutorial program. In
addition to guiding the user through the process of filling out

Issue 16 C News 6

copyright applications, the user can learn quite a bit about
copyrights by using the full program. The program describes
what a copyright is, what can be copyrighted, why works should
be copyrighted, and other information. In addition, the program
discusses what additional protection, other than a standard
copyright, is available for software.

After all this information and a list of a few last minute
instructions, the program's main menu appears, offering the user
a choice of completing Form TX or Form PA. (Form PA is for
copyrighting screen output and requires an additional module,
which is available for $19.25.) The next screen is a listing of
all the entries on side one of Form TX. A set of default
information is already entered and can be written over. This
information is, according to Synthetic Intelligence,
representative of 80% of the copyright applications which are
filed. There is no reason to doubt this claim, as the default
information basically consists of the title, author's name,
addresses, etc. After completing the first half of the form,
the program asks if the information is correct and if the
printer is ready. If the paper is not properly aligned in the
printer, the user is allowed to set the paper before printing.
This is probably the biggest drawback to the program, because a
user might want to fill out an entire form before printing.

After printing the first page, COPYRIGHT-IT guides the user
through the completion and printing of the second page. After
the second page is completed, the program displays one last
screen of information, consisting of what steps the user must
follow to send the form (i.e., the $10 filing fee and the
address and phone number of the Copyright Office) and
instructions on how to obtain, if necessary, special handling
(for $200).

COPYRIGHT-IT has a comprehensive help system, with help
available for each data field. To obtain help on a particular
item, all the user has to do is press "F1" and a definition of
that particular field appears. If additional help is required,
the user can display an interpretation of that data field and an

All in all, COPYRIGHT-IT is a good program. It greatly
simplifies the completion of Form TX and contains a quite a bit
of useful information. As good as COPYRIGHT-IT is, it is not
without its drawbacks. At times it runs a bit slow, which can
be especially annoying on a slower machine. The biggest
drawback, however, is that COPYRIGHT-IT is designed to print
each side of the form as soon as it has been filled out. It
would be preferable if the entire form was completed first and
then the user was given an option to save the data or print the
form. When the data entry section of the program appears, it
contains the information entered the last time the program was

Issue 16 C News 7

run. While this is not a problem, there is no way to save
information each time the data is entered, so a separate data
file cannot be maintained for each application. The main menu
should also be expanded, allowing for these options, that is
allowing the user to retrieve a saved data file and to just
print a file.

In spite of these minor drawbacks, COPYRIGHT-IT is a
valuable program, well worth its cost. With COPYRIGHT-IT, there
is no reason for any programmer not to copyright his software
just because he thinks filling out the appropriate forms is

Issue 16 C News 8

BEGINNERS CORNER: By Wayne Dernoncourt

It's time for the showers so that we can have May flowers.
Flowers are the result (output, if you will) of water, sun and
seeds (inputs, if you will). With that as an introduction, I'll
continue the series of articles on C and doing input to a C
program. This month, we'll do basic data entry from the
keyboard. In a future article, we'll discuss reading and
writing to files, as well as other methods of reading the

The subject of data entry is confusing to say the least.
This isn't to say that is impossible, just that it's difficult
at times to understand. The basic command required for this is:

scanf ("arg.list.1", arg.list.2);

As you can see the scanf function accepts two argument lists.
The first argument list looks like the argument list that
describes variable output on the printf function. The second
argument list lists the variables that are to be filled from the
first argument list. This is different from the printf function
since the second argument list was optional. If it wasn't
given, the only thing printed was the text from the first
argument list. If both argument lists aren't present in the
scanf function, then the compiler will have a difficult time
either interpreting how to read the data from the keyboard, or
where to store the data.

If you'll remember from the discussion on the printf
function, the basic format of the first argument list was a
series of variable formatting commands %%f, %%d, %%c, %%s, etc.,
interspersed with text to print. These are consistent and are
used with the scanf function.

Also from the discussion on the printf function, the basic
format of the second argument list was a list of variables
separated by commas. This is the part that is a little bit
confusing to some people. On the scanf function, there is still
a comma separated variable list, but with a change, each
variable that isn't a character or string variable is preceded
with a &.

As a refresher, I'm going to list the two source files that
I've changed (INIT.C & GET_DATA.C). After the two source files
is a discussion as to why they were changed and their affect on
the other modules. The first module is the main module and goes
into a file called INIT.C.

Issue 16 C News 9

float get_data (int samp_size); /* This has changed */
float compute (int samp_size, float x_sum);
void print_results (float average);

main ()

/* This program is to find the mean (average) and standard
deviation of a series of numbers. The numbers will be read in
from the keyboard and printed on the screen. Enter -1 when
finished */

/* initialization of variables */
/* 1. Declare all variables needed and initialize them to zero.*/
int samp_size=0; /* samp_size: number of variables read in*/
float sum_of_x=0.0; /* the sum of the variables read in*/
float answer;

samp_size = 4; /* Get four data points from the keyboard */
/* The location of this statement changed */

/* get the data needed by the program */
sum_of_x = get_data(samp_size); /* This has changed */

/* Now compute the answer */
answer = compute(samp_size, sum_of_x);

/* Print the results out */
print_results (answer);

/* Closing the brace on the main routine exits the
program. There are other ways out, but this way will do for

The following goes into the file called GET_DATA.C. Notice the
changes that have been made (go back and compare the program
from the November column).

/* 2. Get samples from the keyboard. The number of samples to
read will be controlled by a number passed to this function
by the calling program. */

float get_data(int samp_size) /* Statement change */
float sum_x=0.0, sample; /* Statement change */
integer i;

for (i=1; i { /* is new. */

Issue 16 C News 10

printf("\nEnter sample point: %%d", i);
scanf ("%%f", &sample);
sum_x += sample; /* New group ends here */
/* Now is the time to return back to the main program. */

There are three big changes which you may notice. First
and maybe the most straight-forward is the addition of the
integer variable samp_size to the get_data prototype in the
INIT.C file along with it's addition to the function call and
subsequent declaration.

The second is the construct for (i=1; i a set of curly braces ("{}") enclosing some C reserved words.
This is the basic loop control mechanism in C. There are
variations on this, and they all have their uses, but this is
the basic one. There are four sections to this construct. The
first, i=1, initializes the variable i (it still has to be
declared as being accessible to the function). This
initialization can be to any value, including a variable. The
second section is the test section, as long as this section is
true, do the C statement following it. The third section is the
action to be performed after the loop section has executed. The
fourth section is the whole reason for the loop mechanism to
exist, that is the set of actions the program is supposed to
perform, the C commands inside of the curly braces. If you will
remember in the November issue, I said that to C, the following
two sentences were equal:



In English, this is the same.

The curly braces group a set of statements that are to be
executed every time the loop is executed. Each of the sections
may contain any valid C expressions. As long as the second
section evaluates to true the loop will be executed. The
expression that you may have noticed in the third section, i++,
but couldn't quite decide what it does is called the post
increment operator. If you examine a lot of programs, a lot of
the time in looping is spent incrementing something by one. The

Issue 16 C News 11

people that designed the language realized this and decided to
take advantage of this by using an instruction that is found on
a lot of CPUs called the increment instruction. The increment
instruction is faster for the CPU to execute and is also easier
for the programmer to see what is going on. It may look awkward
at first, but after you get used to it, it is very powerful. By
the way, there is also a decrement operator. I'm going to
reserve the issue of these operators until a later issue.

The third thing that you may notice, and the point of this
whole discussion is the scanf command. Notice the similarity
between scanf and printf. The biggest difference is the
addition of the & in front of the variable to receive the value
read in from the keyboard (remember this is only used for
integer and real numbers, not for characters or strings). In a
next months column, I'll discuss what the & is and other ways it
can be used.

Issue 16 C News 12

SETS IN C (V1.0) by Arnold Cherdak

Before I "fell in love" with C, I, like many others, wrote
a great deal of software in Pascal. Indeed, my recent pursuit
of a Master's Degree in Computer Science has resulted in a large
number of projects, etc., written in Pascal. Despite my
affection for C, I must admit to it having some shortcomings
compared with Pascal. In particular, Pascal's facility with
sets is sorely missed by me in C. I have seen some approaches
to C set implementations and have tried to use them. However,
they either were very incomplete or suffered from being part of
another software package so I lost patience before I was able to
understand them. This effort is an attempt to provide a
complete capability with only a few omissions and, I must
confess, also attempts to use some of the features I liked best
in other approaches.

In Pascal, I was/am regularly able to write a convenient
expression such as the following:

IF X IN ['A'..'F','a'..'f'] THEN ...

Or, if I had assigned the character ranges to a SET OF CHAR
variable, earlier, I could have said

CHAR_VAR := ['A'..'F','a'..'f'];

To provide that facility in C along with all the other neat
things that can be done with Pascal's sets required several
steps, namely:

Issue 16 C News 13


This wasn't too difficult since I started with several good
references including the following:

1983, W.W. Norton & Co., New York.

Addison-Wesley, Reading, Mass.

[3] The Institute of Electrical and Electronics Engineers,
770X3.97-1983), 1983, Wiley.

A set is defined [1] as a group of values of any data type
that is enumerable. That is, the values of the type can be
numbered and can be compared for equality and relative
position. They are, in other words, ordinal.

The particular data type of which the set consists is
called the set's base type. When performing certain operations
on one or more sets, it is only logical that all sets involved
in the operation have the same base type. For example, you
wouldn't want to add apples to oranges unless, of course, you
were making fruit salad. This brings about a requirement for
type checking in set operations.

The C language has, as does Pascal, a number of ordinal
data types as listed below:

enumerated types

Boolean types have only two values, TRUE and FALSE. These are,
however, ordinal, and can form a legitimate set.

Integers are an infinite sized set and for practical
purposes are limited by the maximum integer value representable
on the computer in use. For typical personal computers, a
16-bit integer would have a maximum value of 32K (signed
integers). This is really a subrange of integers and I decided
to remove the type integer and allow subrange to represent
integer types in the practical sense.

Issue 16 C News 14

While negative values can be ordinal and sets in Pascal can
be of negative values, this complication was avoided for the
current release of "sets." I have not tested the code with
negative set member values and I don't know what would happen if
they were used. I'll look into that in the future.

Character type is a common type of set base type, at least
in my own software. The basic implementation is capable of
handling a full 256 character set.

Finally, Enumerated types are a primary feature of Pascal
and sets of these types are commonly used. ANSI C makes
provision for Enumerated types but without type checking.
Subranges of Enumerated types are, of course, allowed.

Given all the above base types, the next step was to
determine what operations were to be performed on sets of these
base types. For this I used references 1 and 3 and made a list
of operations on sets that were required by the industry Pascal
standard. The following is the list of operations I gathered
from these references:

a) Define a set type and a NULL set

b) Construct & populate a set

c) Assign a set value to a set variable or from one set to
another and add or delete members of a set.

d) Perform set multiplication (intersection), addition
(union), and subtraction (difference)

e) Perform relational test operations namely a = b set a
equals set b a <> b set a does not equal set b a <= b
set a is included in set b a >= b set a includes set b
a IN b ordinal value, a, is a member of set, b

f) In addition, several operations not found in the Pascal
standards were considered desirable including the
ability to display set values in several ways.


First, I needed to define the data type, set. Well, it
needed to have a base type as discussed above. It needed to
accommodate as many as 32K members and, more typically, only 256
members while not consuming enormous amounts of storage. It
needed to be easily definable within a C function and it had to

Issue 16 C News 15

disappear automatically when the function execution was done or
when the program needed it to disappear. When it disappeared,
it could not consume storage.

The C structure was the logical result and is shown below
along with a definition of the base types allowable:

/* Base Types come from an enumerated type definition. */
typedef enum {UNIVERSAL, BOOLEAN,

/* The following structure IS a set */
typedef struct SET {
base base_type; /* base ordinal type for the set */
int set_size; /* max allowable set size */
int nmembers; /* number of members assigned */
int member_recs; /* number of member-holding words*/
int set_tag; /* additional typing feature */
/* member-holding words*/
} set;

Each instance of a set object is a set variable or set. Set
creation is performed by defining a set object using normal C
defining statements such as

struct SET set_name;

The base_type field was explained previously.

The set_size field indicates the maximum number of set
members allowable under this particular set definition. This is
not to be confused with the amount of member storage permitted
in the array, "word."

The nmembers field denotes the number of set members
currently assigned to the set. For example, if a set of
CHARACTER is defined to have a set_size of 256, it could
conceivably hold as many as 256 set_members. If only 'A'..'Z'
were assigned to the set, then nmembers would contain the
number, 26. It follows logically that a set without any members
-- i.e.- nmembers = 0 -- is an empty or a NULL set.

The array, "word," contains a number of words (unsigned
integers) determined by the constants MAX_MEMBERS and
MEMBERS_PER_WORD. These constants and their definitions may be
found in file, SETS.H, and are implementation-specific. Feel
free to alter them but note that MEMBERS_PER_WORD is a physical
limitation for most Personal Computers.

Note that all sets will have an array, "word," of the size

Issue 16 C News 16

determined here. However, the number of "word" array values
used for a set may be less than this. For a 16-bit integer
machine and MAX_MEMBERS = 256, the word array will have 16
values (256/16). If the set_size is 20, only two values in the
word array are required and the member_recs field will contain
the value, 2. The remainder of the word array will be present
but unused.

With the default values for the constants given in SETS.H,
each set definition will require 42 bytes on a typical Personal
Computer using Turbo-C. If the value of MAX_MEMBERS is raised
to 32767 (max value for a signed integer, i.e.- nmembers, in
Turbo-C, Version 2.0), 2058 bytes would be required for a single

Finally, the set_tag field is an additional means for
defining set type. For example, definition of a set of values
for the first letter of valid credit cards may be set_size=10
and base_type= CHARACTER. It wouldn't do to be able to combine
that set, inadvertently, with a set of question responses which
might also be of set_size=10 and base_type=CHARACTER. To
prevent that type of an error, assign a value to the set_tag
field and the required type checking will be carried out by the
sets software. In the examples presented with this package,
set_tag is always made 0.

In defining a set, it is required to initialize certain of
the structure fields including base_type, set_size, set_tag, and
to give the set a name. This could be left to the user who
would have to know about initializing structure field values.
However, I felt that this job should be made a bit simpler if
possible. A macro called "defset" was written to create the
structure and to perform the required initialization. While the
user still has to enter the initial values, it seems easier to
express them as function arguments rather than as initialization
values. Defset is shown below:

/* This macro provides a set declaration and should be used
whenever a set object must be declared.
#define defset(set_name,bastype,size,tag) struct SET set_name\
= {bastyp,size,0,((size/MEMBERS_PER_WORD)\

To use defset to define a set in a function, merely enter


in the same location at the top of the function where other
variables are defined and the C preprocessor does the rest. Use
the set as you would any other structure. You may examine its

Issue 16 C News 17

contents or you may use the functions in "sets" to manipulate
the structure. It would be best not to alter any of the
structure fields by any means except through the "sets"
functions since all the field values are needed by "sets."

The functions required to perform the list of operations
presented above are listed below as function prototypes together
with brief descriptions of each function:

a) void dump_set(set *aset);

This function dumps a description of a set out to
stdout. The function uses the argument, pointer to a
set, to get to the set data.

b) void set_print(set *aset);

Prints current members of the set. The function
uses a pointer to a set to get to the set data.

c) unsigned wordlength(void);

This determines the number of bits in a standard
unsigned integer. This is not a "sets" function. It's
a convenient way to determine the number of bits in an
integer, however.

d) int add_member(set *aset, int member);

Sets a bit in the member'th bit place of the set's
member record. Takes a pointer to a set and a set
member ordinal value and returns constants SUCCESS if
the set accepted the new member, NOCHANGE if the set
already had that member present, or FAILURE if the
addition failed.

e) int del_member(set *aset, int member);

Resets a bit in the member'th bit place of the
set's member record. Takes a pointer to a set and a set
member ordinal value and returns constants SUCCESS if
the member was deleted, NOCHANGE if the set already had
that member deleted, or FAILURE if the deletion failed.

f) boolean in_set(set *aset, int entity);

Determines if entity is a member of the set. Takes
a pointer to a set and a set member ordinal value and
returns constants TRUE if the set contains the member
specified by the ordinal value and FALSE if it does

Issue 16 C News 18

g) int set_assign(set *destination, set *source);

This function assigns a set value to a set variable
or the value of one set variable to another. Takes a
pointer to a source set and a pointer to a destination
set. Returns SUCCESS if the assignment is made and
FAILURE if it is not.

h) void set_clear(set *aset);

This function clears all members in a set. Takes a
pointer to a set and deletes all set members to form an
empty set.

i) int check_set_types(set *set1, set *set2);

Type checking is done here in three ways:

The base_types of destination and source must be
the same and both destination and source must have the
same set_size and set tag. UNLESS, of course, one of
the base_types is UNIVERSAL. Takes pointers to two sets
and returns SUCCESS if for UNIVERSAL base_type, set_tags
are equal and the set containing the UNIVERSAL base_type
has a larger or equal set size than the other set. If
no base_types are UNIVERSAL, SUCCESS is returned only if
base_type, set_tags, and set_size are the same for both
sets. Otherwise, FAILURE is returned.

j) int set_intersect(set *intersect, set *set1, set *set2);

This procedure computes the intersection
(set-product) of two sets. The sets must have the same
base_type in order for this to work. The input
parameters are left unchanged. Takes pointers to two
input sets (set1 and set2) and an output set that will
contain the intersection of the two input sets. Returns
SUCCESS if the intersection can be computed, otherwise,
FAILURE is returned.

k) int set_union(set *xunion, set *set1, set *set2);

This procedure computes the union (set-sum) of two
sets. The sets must have the same base_type in order
for this to work. The input parameters are left
unchanged. Takes pointers to two input sets (set1 and
set2) and an output set that will contain the union of
the two input sets. Returns SUCCESS if the union can be
computed, otherwise, FAILURE is returned.

l) int set_difference(set *difference, set *minuend, set

Issue 16 C News 19

This procedure computes the difference of two
sets. The sets must have the same base_type in order
for this to work. The input parameters are left
unchanged. Takes pointers to two input sets, subtrahend
which is subtracted from the minuend, and an output set
that will contain the set difference. Returns SUCCESS
if the difference can be computed. Otherwise, FAILURE
is returned.

m) int set_member_count(set *aset);

Returns the number of members in a set. Takes a
pointer to a set.

n) boolean set_equality(set *left, set *right);

Two sets are equal if they have the same type and
size and the identical membership. Takes pointers to
two input sets and returns TRUE if the sets are equal
and FALSE if they are not equal.

o) boolean set_inequality(set *left, set *right);

Two sets are equal if they have the same type and
size and the identical membership. Takes pointers to
two input sets and returns TRUE if the sets are NOT
equal and FALSE if the sets ARE equal.

p) boolean set_included_in(set *left, set *right);

The left set is included in the right set if every
member of left is a member of right (left <= right).
Takes pointers to two sets and returns TRUE if the left
set is included in the right set and FALSE if it is


q) boolean set_includes(set *left, set *right);

The right set is included in the left set if every
member of right is a member of left (left >= right).
Takes pointers to two input sets and returns TRUE if the
left set includes the right set and FALSE if it does

r) boolean cmp_base_types(set *seta,set *setb);

Compares base_types of two sets. Takes pointers to
two sets and returns TRUE if one of the sets has
UNIVERSAL base_type or if both sets have the same
base_type. FALSE is returned, otherwise.

Issue 16 C News 20

s) boolean cmp_set_tags(set *seta,set *setb);

Compares set_tags of two different sets. Takes
pointers to two sets and returns TRUE if both sets have
the same set_tags.

t) int set_of(set *aset,...);

This function assigns a set of values to a set
variable after clearing any contents of that variable.
The variable's parameters must be able to accommodate
the set of values. Takes a pointer to a set followed by
set constructor expressions. The set constructor
expressions are followed by an End-Of-List symbol
consisting of an under- score character followed by a
capital E, or, _E. Constructor expressions are almost
identical with those used in Pascal with the exception
that subrange limits are separated by two consecutive
underscore characters (__) rather than two dots (..) as
in Pascal. Typical constructor expressions might
include the following:


In the above example, a CHARACTER set is populated with
upper and lower case alphabets; character 1 (i.e.
Control-A); and character 92, a backward slash.

u) int set_args(set *aset, va_list ap);

Extracts all the set members from a parameter list
passed to the caller of this function. This function is
for internal use by the set_of function.


The functions and definitions discussed above are
implemented in Turbo-C, Version 2.0 and are contained in files
SETS.C and SETS.H. In addition, a test file, SET_TEST.C, is
included to illustrate the use of "sets." I tried hard to keep
the implementation as close to ANSI C as I could. However, the
only ANSI C compiler I have access to is the Turbo-C compiler.
Perhaps someone with some other ANSI compilers would run the
test program and include the results in the same archive file
just to prove whether sets can be run someplace other than under

Issue 16 C News 21

Sets was a project that occupied me for about a solid week
over a period of a few months. I'm looking forward to having
the set capability for my C programs and I suspect that my time
investment will be paid back quickly. I hope you get some use
out of it as well.

4. THE SETSX.LIBraries

Having made the sets functions, I realized that each time
they were used, the resulting executable module increased in
size by about 2500 bytes. I felt this was too large an increase
despite the neat new capabilities so I decided to create some
libraries so I could use just the functions I needed thereby
incurring minimum code size penalty. Happily, Borland makes it
relatively easy to create libraries with their MAKE and TLIB
utilities. The following is a "cookbook" to tell you how I did
it and, hopefully, it isn't too ridiculous:

As I said above, an advantage of having functions in
libraries is that you may use functions from a large collection
without having to link all your clever code into each program.
This is achieved in a very straightforward manner; by breaking
the code into use-sized pieces or single functions, compiling it
as individual functions to form individual linkable object
modules, and then collecting them in a single file or library so
that your linker can extract them individually as needed for
your programs. Oh yes! One important thing. All the object
modules in a single library must be compiled for the same memory
model. If you work with more than one memory model, you will
need a "sets" library for each memory model you use.

Borland's MAKE program is usually used to generate software
using compilers and linkers. I used Borland's TCC and a library
manager, Borland's TLIB. I used several files to describe the
end result, six library files, one for each of Borland's memory
models. The MAKE program required a makefile which I called
SETS.MAK. The makefile referenced TLIB which, in turn, called
upon a response file called SETS.RSP. Being a neophyte to the
use of MAKE, I took the easy way out and used a batch file to
call MAKE six times and I passed model-determining parameters to
MAKE each time in order to create the six libraries. These files
are provided with this article for your use.

When you review these files, you will, no doubt, be a bit
taken aback by the path notation used throughout. This was a
consequence of the subdirectory structure I happen to be using.
It was necessary to carefully indicate the directory structure
to MAKE, etc., to achieve a usable result. My subdirectory
structure is as follows:

Issue 16 C News 22

____________________________|______________ Object Module
| | | Subdirectories
MAKE.EXE Subdirectory |-------"OUTPUT.S"
TLIB.EXE | |-------"OUTPUT.M"
| |-------"OUTPUT.C"
C Source Code |-------"OUTPUT.L"
for SETS |-------"OUTPUT.H"
LIB files for
LST files for

The MAKE program runs other programs according to the
instructions contained in a text file. The layout of this .MAK
file is as follows:

column 1
# This is a comment. It ends whatever line it's found on.
# It can begin in any column.

<<< blank lines are permitted >>>

# Macro for compiler directory locations...This defines the
# compiler and the locations of all the required libraries,
# include files, and a place to put the output .OBJ file.
# Note that the destination for the compiler output is,
# itself a macro expansion. In this case, the macro, MDL,
# is supplied on the MAKE command line in the file, MAKESETS.BAT.

COMPILER = d:\tc\tcc -c -C -Ld:\tc\lib -Id:\tc\include \

# The first "executable" line of the .MAK file defines the
# product of the MAKE operation. In this case, it's a library
# file called SETS$(MDL).LIB. Note the full path specification
# qualifying all the filenames. The backslash, \, is used as a
# line continuation signal for MAKE.

d:\tc\sets\SETS$(MDL).LIB: d:\tc\output.$(MDL)\DUMPSET.OBJ \
d:\tc\output.$(MDL)\SETPRINT.OBJ \
d:\tc\output.$(MDL)\SETOF.OBJ # last OBJ file

Issue 16 C News 23

# The colon after the product signals the beginning of the list
# of files that the product is dependent upon. If any of the
# times/dates of the dependencies are after those of the product,
# the product will be re-created according to the rules. Or, if
# the files don't exist they are created. In this case, the rules
# are

cd \tc\output.$(MDL)
d:\tc\tlib d:\tc\sets\sets$(MDL).lib /E @d:\tc\sets\sets.rsp,\
cd \tc\sets

# Product-specification/dependency entries begin in column 1 and
# rules begin in columns other than 1 (i.e. after a tab or space).
# In this case, the rules require a switch to a subdirectory
# determined by the MDL macro followed by operation of the TLIB
# program which combines all the object files defined in a
# response file (consisting of all the modules in the library)
# and a switch back to the original directory.

# The dependency concept is carried a step further, however, by
# adding additional "executable" lines to the .MAK file. The
# same format is used as for the main product as shown below:

d:\tc\output.$(MDL)\DUMPSET.OBJ: d:\tc\sets\dumpset.c \
$(COMPILER) -m$(MDL) d:\tc\sets\DUMPSET.C

# In this case, one of the .OBJ files is the product and it's
# dependent upon its C source code as well as a special
# purpose header file. If the date/time of either of these files
# is later than that of the .OBJ file, the rule(s) following the
# product line will be executed. Note that MAKE follows the chain
# of dependencies down to its end before actually executing the
# rules. Note that in the above executable lines for DUMPSET.OBJ,
# the COMPILER macro is used to direct the compiler to the proper
# subdirectories. The Turbo C Reference Guide, Appendix D,
# contains instructions and more features for the MAKE program.
# Instructions for TLIB are contained in the same place.


With Turbo C's integrated environment, it's really easy to
use the SETS libraries. Use a project file (.PRJ file) and at
the end of the .PRJ file, add a line with the name of the .LIB
file you want to use. The following is the .PRJ file used to
make the SET_TEST.EXE program included with this article using
Turbo C's "huge" memory model.

Issue 16 C News 24



Simple enough. The first line tells Turbo C to compile
SET_TEST.C and the last line tells the linker to search
SETSH.LIB for referenced but not yet found object modules before
searching the standard, CH.LIB. Press the MAKE function key and
it's done.

With the command line compiler, TCC, just use the same list
of files as you would in the .PRJ file as follows:

tcc -mh -Id:\tc\include -Ld:\tc\lib set_test setsh.lib

In both cases, the linker will look for all the SETS
libraries located in the d:\tc\lib subdirectory unless you have
indicated that .LIB files may be found elsewhere.

If you have used the correct invocations of the SETS
functions as described above, you will correctly link in the
needed functions and you've got sets capability in C.

Issue 16 C News 25


All articles, reviews and letters to editor should be
submitted in a ASCII formatted file. Please use 0-65 margins,
and single space. Do not format the text in anyway, as I use
Proff to format C News. Proff takes care of the justification,
footnotes and headers.

You can send in your article on a diskette to the C BBS, or
upload it to the C BBS. See "How to Contact us here at C News"
for more information.


Issue 16 C News 26


The primary address for C News is as follows:

C News

% BCL Limited

P.O. Box 9162

McLean, VA 22102


The primary electronic address for C News is the C BBS:



2400,8,N,1 23hrs a day.

1:109/307 in Fidonet.

The secondary electronic address for C News is:

MCI Mail: BCL Limited


 December 14, 2017  Add comments

Leave a Reply