ECE 209 Rest of Chapter 14

Unions

The union is a structure in which only one field can be active. The syntax for accessing union fields is identical to the syntax for accessing structure fields.

Unions are confusing.

Color example

Color can be represented in many ways.

union Color {
  float hsb[3] ;
  int   rgb[3] ;
}

union Color Red, Blue ;
Red.rgb[0] = 255 ;
Red.rgb[1] = 0 ;
Red.rgb[2] = 0 ;
Blue.hsb[0] = 0.6666666 ;
Blue.hsb[1] = 1.0 ;
Blue.hsb[2] = 1.0 ;

But how can you tell there RGB from HSB?

struct Color {
  int   type ;    /* 0 for HSB, 1 for RGB */
  union uc {
    float hsb[3] ;
    int   rgb[3] ;
  }
}

struct Color Red ;
Red.type = 1 ;
Red.uc.hsb[0] = 255 ;
Red.uc.hsb[1] = 0 ;
Red.uc.hsb[2] = 0 ;

Issues

Enumerated types

Enumerated types are a great way to assign logical numbers to useful integers. They look better those DEFINE's in the ICMP include file.

/* p. 575 of textbook */
enum spectrum {red, orange, yellow, green, blue, violet} ;
enum spectrum color ;
enum ececourses {ece109 = 109, ece209 = 209} ;

Functions as parameters

In C, functions can be passed function pointers, but not functions.

/* Function to perform a numeric integration */
double Intergrate0to1(double(*f)(double), int N) {
  double sum = 0.0 ;
  int i ;
  sum = f(0.0)*0.5 ;
  for(i=1; i < N-1; ++i)
    sum += f(1.0/N) ;
  sum += f(1.0)*0.5 ;
  return sum/N ;
}
/* Prototype for the standard C quicksort routine */
void qsort(void *base, size_t nmemb, size_t size,
           int(*compar)(const void *, const void *));

struct course {
  char Dept[4] ;
  int  Number ;
}

int CompareCourses(const void *V1, const void *V2) {
  struct course *C1 = (struct course *)V1 ;
  struct course *C2 = (struct course *)V2 ;
  int R = strncmp(C1->Dept, C2->Dept, 4) ;
  if (R)
    return R ;
  else
    return C1->Number - C2->Number ;
}

void SortCourseArray(struct course ManyCourses[1000]) {
  qsort((void *)ManyCourses, 1000, sizeof(struct course), CompareCourses) ;
}

Resolving or accepting inconsistencies?

These are also valid ASNI C.

double Intergrate0to1(double(*f)(double), int N) {
  double sum = 0.0 ;
  int i ;
  sum = (*f)(0.0)*0.5 ;
  for(i=1; i < N-1; ++i)
    sum += (*f)(1.0/N) ;
  sum += (*f)(1.0)*0.5 ;
  return sum/N ;
}
double Intergrate0to1(double(*f)(double), int N) {
  double sum = 0.0 ;
  int i ;
  sum = f(0.0)*0.5 ;
  for(i=1; i < N-1; ++i)
    sum += f(1.0/N) ;
  sum += f(1.0)*0.5 ;
  return sum/N ;
}

The functional

int Always(int ID) {
  return 1 ;
}

int Perhaps(int ID) {
  return ID%7 == 3 ;
}

int Never(int ID) {
    return 0 ;
}

/* Array of ID checkers */
int (*IDChecker[5])(int ID) = { Always, Always, Perhaps, Never, Always } ;

/* Function to see if ID checker accepts 0 as ID */
int TestIf0Accepted(int(*f)(int ID)) {
    return (*f)(0)==1 ;
}

/* Function to test if function to test ID checker really does */
int TooDurnComplicated(int(*T)(int(*f)(int ID))) {
    return (*T)(Always) ;
}

/* You really don't need that f or ID in the parameter list */
int TooHardToRead(int(*T)(int(*)(int))) {
    return (*T)(Always) ;
}

/* Function to test if function to test
 *                  if function to test ID checker really does */
int WasntTheLastOneEnough(int T(int(*)(int(*)(int)))) {
    return (*T)(TestIf0Accepted) ;
}

Complex declarations

  1. overriding parentheses go first
  2. postfix functional parenthesis and array braces go next
  3. prefix pointer astericks go last

Try out these examples from the textbook

Try out some examples from the functional sections