C Programming

Download Report

Transcript C Programming

C Programming
Program Quality
Some of the material in these slide is adapted from chapters 5 and 6
of “Code Complete” (see course resource page)
A high-quality project
•
Ease of understanding
– Readable by someone who did not write the code
•
Ease of implementation
– Small cohesive pieces are easy to code
•
Ease of testing
– Each operation can be tested separately
•
Ease of modification
– What to change is easy to identify
•
Correct translation from requirements
– Easy to identify the code that implements each requirement
Top-Down Design
• A central part of programming in a language like C is taking
a large and complex problem and decomposing it into
smaller problems that can more easily be solved.
• This is not a one step process -- we further decompose the
sub problems into sub-sub problems until the problems are
eacg easy to solve
• Real life examples
– Bake a cake
– Mow the lawn
• Each sub-problem becomes a component
Program Components
• In languages like C, component refers to a routine
or module
– A routine is a function or main program
– A module is a collection of routines, data, variables, etc.
• Typically one C source file and associated header file
• Components…
– hide internal details and processing from one another
– hide design decisions
• When a hidden design decision changes, only that component
must be changed.
– isolate complex parts of problem, where "decisions" need to be
made.
– provide layers of abstraction and information hiding
Why Use Functions?
• Reduce Complexity
– Most important reason
– Hide information
– Look for deeply nested loops and complex Boolean expressions
• Avoid Code Duplication
– Code will be more reliable and easier to modify
• Improving performance
– Optimization occurs in just one place
• Promoting Code Reuse
• Isolate Complex Operations
– Complex algorithms, tricky Boolean tests
High-Quality Functions
•
A high-quality function is like a black box - you know the inputs
and outputs, but not what happens inside
•
A high-quality function has a well-chosen name
–
A verb followed by a noun. The name should reflect what the function does
• printGreeting( )
• getPositiveInteger( )
–
A descriptive name of what’s returned
• sin( )
• nextRandomInt( )
–
Avoid vague names
• outputReport( )
• performUserInput( )
–
Follow naming conventions
Function Cohesion
• Cohesion refers to how closely the operations in a function
or module are related.
– Strive for a high degree of cohesion
• Strong cohesion results in code with high reliability
– A study of 450 FORTRAN routines found that 50% of highly cohesive
routines were fault free. Only 18% of routines with low cohesion were fault
free.
Functional Cohesion
• A function that performs only one operation
–
–
–
–
calculateAge( ) -- Calculates a person’s age, given their birthday
getFileName( ) -- Gets the name of a file from the user
displayStudenNames( ) -- Displays student names to the screen
appendValue( ) - adds a new value to the end of an array
• Strive to achieve functional cohesion whenever
possible.
• Functions with functional cohesion are easy to
name. If your function isn’t easy to name, that’s a
hint it may not have functional cohesion.
Sequential Cohesion
• A function with operations that must be
performed in a specific order, with the output of
one operation being the input to the next
– A function that
• Inputs the number of students
• Inputs the final exam grade for each student
• Calculates the min, max and average final exam grade
• Displays the student grades
• Displays the min, max, and average grade
• Sequential cohesion is acceptable but can often
be improved by writing separate function.
Communicational Cohesion
• A function that performs operations on the same
data but are not otherwise related
– A function named getNameAndChangePhoneNumber( ) that
retuns the name from, and modifies the phone number in a
structure of student information
• Communicational cohesion is considered
acceptable if necessary for practical reasons
• Note how the names of these functions are a clue
to their communicational cohesion
Temporal Cohesion
• A function that performs several operations
which are related only because they must be
performed at the same time
– A function named initialize( ) that
• Initializes an array
• Initializes some variables
• Seeds the random number generator
• Prints instructions
• These functions are considered acceptable, but
have them call separate functions for each
operation.
Logical Cohesion
• A function that performs one of several
operations based upon a control flag parameter
– A function that
• Prints student name OR
• Inputs the student’s age OR
• Prints a class roster OR
• Prints a list of faculty members
• Fix this by writing a separate function for each
operation.
Procedural Cohesion
• A function that performs operations in a specific
order. Unlike sequential cohesion, these
operations do not share the same data
– A function that
• Prints a revenue report
• Prints a report of expenses
• Prints a list of employee names and office numbers
• Fix this by rethinking your design
Coincidental Cohesion
• Virtually no cohesion at all
• A function that performs unrelated operations
– A function that
• Checks for new email messages
• Prints a list of students in a course
• Changes my Unix password
• Fix this by making a separate function for each
operation
Function Cohesion Sumary
• There are several generally accepted levels of cohesion
listed here from worst to best.
– Coincidental - a function that performs several unrelated operations
– Logical - a function that performs one of several operations selected by a
control flag passed to the function as a parameter
– Procedural - operations performed in a specific order
– Temporal - operations combined into one function because must all be
performed at the same time (e.g. initialization)
– Communicational - operations make use of the same data but are not
related in any other way
– Sequential - contain operations performed in a specific order, share data
from step to step, but don’t make up a complete function when done
together
– Functional - a function that performs one and only one operation
• Only functional, sequential, communicational and temporal
are considered to be acceptable levels of cohesion
Module Cohesion
• In C, a module equates of a .c source file which
contains several functions and (possibly) data.
• The cohesion of a module refers to how the data
and functions within the module are related.
• Consider the modules data and functions as
whole.
• A cohesive module should contain data and a
group of functions that clearly belong together.
Function Coupling
• Coupling refers to the strength of the connection
between two functions.
– Loose coupling is good, tight coupling should be avoided
– Try to write functions that depend on other functions as little as possible
– A study of 450 FORTRAN routines found that functions with a high
degree of coupling had 7 times more errors than those with a low degree
of coupling
• Common Coupling Criteria
– Size - the number of connections between functions
• Fewer parameters are better
• Primitives are better than arrays or structs
– Intimacy and Visibility
• Parameters are the most intimate (direct) and most visible connection
• Shared data is less intimate and less visible
Data Coupling
• A function passes only the primitive data that the
called function needs
– Most desirable (loosest) form of coupling
int calcRectangleArea( int length, int width);
int sumArray( int array[ ], int size);
int getValidIntFromUser( char prompt[], int max, int min);
Stamp Coupling
• One function passes a struct to another function
– Also known as Data Structure Coupling
– Acceptable if the function uses all or most of the data element in the
struct
typedef struct rectangle {
int height, width;
POINT upperLeft, lowerRight
double diagonalLength;
enum color fillColor;
} RECTANGLE;
void printRectangle( RECTANGLE rectangle);
int calcRectangleArea( RECTANGLE rectangle);
// ok
// less ok
Common Coupling
• Two functions access the same common (global)
data. Acceptable if they don’t change the data.
int myGlobalVar = 99;
int Function1 (int a) {
if (a > 0) {
myGlobalVar++;
a = 0;
}
return a;
}
void Function2 ( ) {
if(myGlobalVar > 0)
myGlobalVar = 42;
else
myGlobalVar = -1;
}
Control Coupling
• A function passes an argument to another
function to tell the called function what to do.
• See “logical cohesion”
• Generally requires the first function to know
about the internal workings of the second
function
Content Coupling
• One function uses code inside another function
(via “goto” statement).
– “tighest” possible coupling
– Never Acceptable
int Func1 (int a) {
printf ("In Func1\n");
a += 2;
goto F2A;
return a;
}
void Func2 (void) {
printf("In Func2\n");
F2A:
printf("At Func2A\n");
}
Function Coupling Summary
• The levels of function coupling are listed below from
low/loose/weak to high/tight/strong
– Data coupling - a function passes only the primitive data another function
needs
• The most desirable level of coupling
– Stamp (data structure) coupling - one function passes a struct to another
function
• Acceptable if the function uses all or most members of the struct
– Common coupling - two functions use the same global data
• Acceptable if the functions don’t change the global data
– Control coupling - one function passes an argument to another function to
tell the 2nd function what to do (see logical cohesion)
• Never acceptable
– Content coupling - one function uses code inside another function (e.g. via
goto statement)
• Never acceptable
Module Coupling
• Module coupling refers to how the module relates
to the rest of the program.
– If the functions in a module are incomplete, outside functions may
need access to the module’s data
• No longer a black box
• A module should provide a complete set of
operations that allow the module’s user to tailor
the operations to his own needs.
Information Hiding
• Information hiding has indisputably proven its
value in practice.
• Integral part of structured programming (in
languages like C) and in OOP
• Most prevalent with respect to modules
• The key is to keep “secrets”
Module Secrets
• Hide design and implementation decision
– Is a “clock” a struct, or just a few independent variables?
– Does the clock keep 24-hour time or 12-hour time?
– What is the format of the input file?
• Secrets are kept through
– The use of static data
– The use of static functions
• The interface (the contents of the .h file) should
reveal as little as possible about how the module
works. A module is like an iceberg -- you can
only see the “top” of it.
Defensive Programming
• Analogous to defensive driving
– Don’t assume that “the other guy” is going to do the right thing.
– Take responsibility for protecting yourself against drunken
programmers
• If your function is passed “bad” data, your
function won’t be hurt.
Note necessarily GIGO
• Garbage In does not mean Garbage Out
• Rather
– Garbage in, nothing out
– Garbage in, error message out
– No garbage in
• Check the values of all input data
• Check the values of all function parameters
• Decide how to handle bad parameter values
– Return false, or other error code
– Print an error message and continue
– Exit your program
assert( )
• When a bad parameter value is fatal to your
function, catch it with assert( ).
• assert( ) is a function which takes a single
Boolean expression as a parameter
– If the Boolean expression is true, nothing happens
– If the Boolean expression is false, an error is displayed and your
program terminates
• Examples
assert( age > 0);
assert ( strlen(filename) < 20);