Cmput 201 - Lecture 5 (With thanks to Jim Hoover)

Case study 3: An Abstract Data Type in C

Software development: bit manipulation package in C.

Implementation at the word or byte level like the Gray Code example of Lecture 3.
In that case we used the basic primitives of C.

But perhaps we want to manipulate very long sequences of (thousands of) bits?

In this case we would need a bitstring abstract datatype. That is, a set of objects and primitive operations, that capture our notion of a string of bits.
In other words an Abstract Data Type

So let's begin by asking ourselves: what is a bitstring?

A bitstring is a sequence of 1' and 0's

How long is the sequence?
Do we allow dynamic adjustment of length, or

do we specify it at declaration time?

How are bits in the sequence identified?
Are they numbered? If so,
what numbering scheme do we use?

For example (left to right, or right to left)

0 1 2 3 ... 31 vs 31 30 ... 3 2 1 0

Do we want to access individual bits, or substrings of bits?

What operations do we require at a minimum? Probably at least put and get.

Then we can implement input and output.

But can we? Not without some idea of length.

Does put modify the original string or generate anew?
As we shall see this leads to an important difference between and abstract data type and a data structure, as well as issues of efficiency.

How do we handle literal constants?
i.e. program text input.

How do we handle type conversions?

Can an int be converted into a bitstring and vice versa?

How is a bitstring initialized?

Do we care about storage efficiency?

time efficiency? programming efficiency?

What about names for our package?

Unique prefix to avoid collisions with library.

What about users of our package?

How do they know what functions are provided and their signatures?

That is, how is the user interface described?

Use a header file to describe the interface

How are we going to handle error conditions and messages?

Should we code our functions assuming that the pre-condition holds, or should we not trust the caller and test with an assert.

What if this is costly?

Our answers to these questions will affect the design of the user interface, and the implementation.

Let's begin with a simple implementation based on the example from the previous lecture.

0. all :: driver :: not important here, for duplicate entries

1. %.o : %.c default processing of .c files

2. depend : use make -n instead

3. bits.o driver.o : multiple objects are OK

4. note make -n and use of touch

5. typedef unsigned int bits

This is how you define your own variable type "bits"

6. macro definition, here looks like a procedure call,

but don't be fooled, this is just a constant of 16 or 32

7. extern ... this header refers to a library function or other independently compiled function.

8. macro definition, beware (x) is not a parameter we are doing type conversion from int to "bits".

9. void main (void); would be enough here, since in

this program there are no parameters

10. bits x note use of shorthand of bits for unsigned int

11. print outputs chars and waits for input

12. scanf("%d%, &x_in); again note &x_in

13. this is x = (x_in) type conversion only

14. x_comp = x when will this not work?

15. bits_length(x) this is an int