CSE 451: Operating Systems, Spring 2011
  CSE Home   About Us   Search   Contact Info 
 
Course Home
Home
Administrivia
Overview
Course email
 
Materials
Course Calendar
Sections
goPost Board
Anonymous feedback
View feedback
 
Assignments
Homework
Projects
Turnin
Gradebook
 
Information
Home Virtual Machine
Linux information
   

Project 0: Part 3 Implementation Details

← Back to main assignment


To help make things clear, the main writeup describes the goals of Part 3 using what should be reasonably familiar C constructs. This addendum explains some unfamiliar C constructs that make implementation cleaner and easier. That is, you should implement Part 3 in the style explained here, not the one used in the main writeup.

The primary implementation problem has to do with type checking, and specifically polymorphism (or lack thereof) in C. As an example, the second argument to math_call is either of two kinds of structs: one encoding two integer arguments, and one encoding four integer arguments. The issue is what the declared type of the second argument should be:

int math_call(int function_name, ??? args, int* result);
The main assignment writeup addresses this by defeating type checking entirely, using void*:
int math_call(int function_name, void* args, int* result);
Now the second argument can be a pointer to anything. The downside of this that the user of math_call doesn't get the benefits of type checking, and so subtle errors can easily arise.

A better solution than void* is to use the primitive form of variable polymorphism that C supports. In particular, we can use the union type. C's union is related to struct, in the sense that you declare a set of fields that comprise the union. For structs, a variable of that struct type contains all of the fields. For unions, a variable of that union type contains just one of the fields - any one. (Technically, C allocates just enough memory to hold the single, largest field, then uses that memory as though it held whichever field the program references.)

Here's mathtable.h, from the skeleton code distribution:

#ifndef MATHTABLE_H
#define MATHTABLE_H

/* function type */
typedef enum {
    ADD,
    SUB,
    MULT,
    SLOPE,
    MAX_FUNC_ID /* to ease boundary checking */
} mathfunctype_t; 

/* generic argument type */
typedef struct {
    int argc;   /* we will choose arguments according to this value */
    union {
        int arg2[2];
        int arg4[4];
    } arg;
} matharg_t;

extern int math_call(mathfunctype_t,const matharg_t *arg,int *res);

#endif  /* MATHTABLE_H */
This declares matharg_t as a struct that has an int field named argc and either a length two or a length four int array. C does not know which it holds; its up to the programmer to keep usage consistent. Basically, whatever code initializes the matharg_t sets argc to either 2 or 4, depending on how many arguments it wants to encode. The code receiving the matharg_t looks at the value of argc to determine how to correctly use the union. C doesn't understand that this is how the struct is being used, so will not detect any misuses, but if the code is correct everything works fine.

You reference the fields of the union just like you do the fields of a struct, for example:

matharg_t myArgs;
myArgs.arg.arg2[0] = 10;
myArgs.arg.arg4[3] = 100;
(Note that those lines are legal C, but don't make much sense. myArgs should be considered to have values in either arg2 or arg4, but not both (at the same time).)

Note that this has solved the type definition issue for math_call: the second argument is now always a pointer to a matharg_t, which can encode either two or four arguments, depending on how it's used.

mathtable.h includes a second change from what is suggested in the main assignment writeup: it uses an enum to define symbolic names for function indices, rather than a series of #defines. The enum is convenient because it automatically makes each successive value increment by one, relieving you, the programmer, of the burden of making sure the list is consistent (e.g., doesn't contain duplicates).


Computer Science & Engineering
University of Washington
Box 352350
Seattle, WA  98195-2350
(206) 543-1695 voice, (206) 543-2969 FAX
[comments to zahorjan at cs.washington.edu]