You are on page 1of 66

CS 204

Advanced Programming

Info, Expectations,
Style, Debugging

1
Couple different items are discussed in these slides:

– Course info
– Good programming practice – style, commenting
– Preprocessor, compiler, linker
– Debugging
– if statements
– using preprocessor directives
– assert statement

2
Info
Topics:
– advanced object-oriented programming techniques and programming with classes
– function overloading,
– templated functions,templated classes
– inheritance
– pointers
– writing better, more efficient programs
– debugging and profiling
– reusable software  (using/creating libraries)
– exception handling (SW interrupts)
– visual/GUI programming
– multi-threaded programming and synchronization,
– network programming (sockets)
– programming in UNIX/Linux environments (make files, shell scripts),

3
Info
These information slides give a summary of what is on the course webpage. You are responsible of
reading all of the info on that site.

Text Book:

Beginning Visual C++ by I. Horton (Chp. 4-18) – for advanced C++ concepts such as classes, inheritance
and GUI programming using MFC. GUI chapters are available in online reserve at IC.

You can also use Tapestry (Chp. 9-13) for some of the advanced concepts.

You may also skip buying a book altogether, or use a favorite other book, as slides are quite
comprehensive.

Webpage: http://people/berrin/cs204/
We will use SUCOURSE only to submit/collect homeworks and discussions. Questions that may interest
other students should be asked on SUCOURSE so that the answer benefits all.

Grading:
– Midterm1: 25% ; Midterm2: 25% ; Final: 30% ; Homeworks: 20%
– There will also be a small amount of bonus (3pts) for instructor’s discretion, based on attendance
and participation.
– There will be about 6 homeworks, each weighting almost equally (100pts, except for the last 2
homeworks which may be 150pts).
– Passing grade: You must have 40 or higher in your total average and 30 or higher in the final
exam, in order to pass the course!

4
Labs and TAs
Lab Schedule: Thursday 5:40 pm - 7:30 pm

Tas will go over course material from the past week and help with that
week’s homework in the lab time. So this is half recitation, half lab hour.

You should preferably go to your own section but in general you can to any
section you want (until further notice).

Any question outside lab or help hours should be sent to SUCOURSE, so


that everyone can see it and the answer.

5
Homeworks
– Through Sucourse only. Anything else will be ignored/deleted.

– Label your homework as


– studentid-FirstnameLastname-hw3.zip
– 5519-AhmetGül-hw1.zip
Failure to do so will lose you points.

– Write your name inside the files as well

– Do not use unknown or uncommon file types that we may not be


able to open (doc, rtf, pdf, ps, zip, rar are fine).

– You may submit your homework multiple times, and you may also
submit late (see below), so make all your submissions there.

6
Homeworks
– Late penalty: Each late day is 10pt off and no homeworks will be
accepted after 2 days in order for the Tas to start grading on time.
Check SUCOURSE for exact due dates for a particular homework.

– Any missing files in your submission (even std. libraries etc.) will
lose you points.

– For complete submission requirements, check the website!

7
Good Programming practices,
Style, Debugging
You will be responsible from the style/practice
guidelines listed here for all future homeworks/projects.

8
Programming
Time spent as a software engineer will be spent mostly on
maintaining and improving/upgrading code:
– 80-90% time
– Yours or others

Avg. # of lines per application:


– 1.2 million!
– It has to be written well so that upgrading/maintaining is manageable

Some old programs are not improved because noone understands the code!

9
Good Programming Habits: Overview
Develop and test your code incrementally
Code defensively
Use modular code
Include debugging code
Include comments

10
MUST Programming Habits: Comments
– How much?: Enough for someone to be able to understand/modify
your code in the future

– When?: Comment when first writing, then as you test and seal code

– You must use sufficient comments as illustrated in the next slide in


each of your homework submissions from now on (penalty: up to
20pts over a 100pts-homework)

– Slide 13 show some different comment styles, but the fact that you
must use comments for each program unit remains unchanged:

– program header (~10-20lines)


– each function and major section (~5-10lines)
– each variable (~1line)
– each paragraph (~1line)

11
MUST Programming Habits: Comments
/******************************************************************************
Purpose: This program is a CD title maker.
Usage: cdmake songlist.txt
Author: Berrin Yanikoglu On the top (program)
Date: 22/2/2005
Any known bugs: It works fine for txt files but crashes on empty input files
References: Any source used besides the ones you used etc.
******************************************************************************/
...
int totalTime; //total time of the songs in CD in seconds
... For simple comments
/***************************************************************************** and variable
This function computes the remaining length in the CD, after explanations
writing all the songs in the input file.
Input: ...
Returns: ...
*****************************************************************************/
int RemainingLength(....)
{ For multiline
... comments and
} major section
headings
/*****************************************************************************/
/************* Process Input and Format Output *********************/
/*****************************************************************************/
int ctr; //counter for ...

12
Examples for various comment styles:
Good Programming Habits:
Naming Conventions
- Naming Style suggestions:
– balanceOwed //alternating - good for normal vars
– RecordsInFile //capitalized - good for Global variables
– MAX_STUDENT_NUM //all caps - good for constants

– e.g. const short MAX_STUDENT_NUM = 1000


– Use this rather than #define

– See http://www.totse.com/en/technology/computer_technology/hungnote.html
for a very structured convention that is used by many software professional
if you are interested.

- I will only ask that you use (all or initial) Uppercase for globals/constants and
otherwise skip to a convention, rather than changing styles.
- No dummy names such as myvar, or Ali_stat, …
- Similarly, dont call your homeworks deneme, test etc. 

14
Good Programming Habits:
Indentation...
- - Indentation, {}
– {}s on the same line or next,
– your code should definitely be indented to reflect the structure
– whatever you choose, adopt and stick to one format

- Use and location of the {}


– Use {}s for clarity - some programmers always use it even for one line loops
– Use {}s on the same line or next, but be consistent

for (i=0; i < NUMCLASS; i++) {


...
}

or

for (i=0; i < NUMCLASS; i++)


{
...

15
Good Programming Habits:
Comments Bad Example

16
Good Programming Habits:
Comments Example
What you should do:
/* swap the two corners */

/* swap the x coordinate */


temp = box1.x;
box1.x = box2.x;
box2.x = temp;

/* swap the y coordinate */


temp = box1.y;
box1.y = box2.y;
box2.y = temp;

17
Good Programming Habits:
Clarity
- - Do not code for compactness
– We are not encoding knowledge: clarity is most important

- Do not use obscure notations


o = 5; value = 1
o = --o - o-- ; res = (value++ * 5) + (value++ * 3);
//Use ++ or -- only, on one line // do not even do this,
even though it looks a little more
innocent

Do not confuse compactness with programming efficiency.


A prime example for efficient programming is to move out unneccessary code out of
loops etc., so that no extra computation is done.
Compactness refers to how short your code is. You don’t want to make your program
unnecessarily long (e.g. two if statements inside one another, even if you could test
for both at once, just as clearly) but not so compact that it is cryptic: rule is to put
only as much code on one line as it is still clearly understandable.

18
Good Programming Habits:
Code development
- Develop and test incrementally
– Rather than writing the whole program first
• I see this as one of the biggest source of frustration when trying to start a project or homework.

- Code defensively
e.g. You try to open a file and without checking that the file is open, you start
reading from it. If the file could not be opened, you get a crash.

Proper form:

ifstream input(filename.c_str());
if (input.fail() ){
cout << "could not open file " << filename << endl;
return 0;
}
19
Good Programming Habits:
Code development
- Other’s code
– You will often have to deal with!
– Add comments as you understand the code, for your sake and others in
the future.

- Don’t ignore warnings


– You should see no warnings when you compile
• E.g. int j - unused variable

• Either change your warning settings (see Warning levels under


Tools/Options) so that it does not report these type of warnings (but then
you are responsible), so that more important warnings do not get
overlooked in a flood of warnings

• Better: eliminate them (go fix them)


i.e. remove that variable etc.

20
Preprocessor, Compiler, Linker

Reminder
Horton Chp. 1

21
Preprocessor
A preprocessor is a program that takes your source file and outputs an
intermediate file (translation unit) before compilation.It does text
substitutions controlled by preprocessor directives, which are lines
starting with # character:

– #include “date.h”:
• contents of the include file is inserted into the translation unit

– #define statements: commonly used to define constants, but const definitions


are preferred
e.g. #define PI 3.1416
#define DEBUG

– #ifdef, #ifndef, #if statements: to conditionally skip parts of the code


• E.g. code in between the ifdef statements are inserted if the preprocessor
variable is previously defined

– #endif, #else, #elif: used in conjunction with the above


22
Preprocessor
– #include statments: contents of the include file is inserted into the translation
unit
– #define statements: to define a preprocessor variable
– #ifdef… statements: code in between the ifdef statements are inserted if the
preprocessor variable is previously defined

Input Output

#include “dice.h” Class dice


#define DEBUG …

}
#ifdef DEBUG
cout << n; cout << n;
#endif

DoSmthg(); DoSmthg(); 23
#define
When the preprocessor sees the directive
#define x right_hand_side
it will replace all occurrences of the identifier x in the source file with the text
right_hand_side.

This is usually used to define constants:


#define PI 3.1416
#define MAXSIZE 10000
#define PROMPT "Please enter your move: "

24
Use const rather than #define
Instead of using #define directives to define constants, as in
#define PI 3.1416

you are encouraged to use the alternative:

const double PI = 3.1416;

But the practice of defining constants using the preprocessor is very


widespread, due to C practice, so you should be familiar with it.

25
Compiler & Linker
The input to the compiler then is the translation unit generated by the
preprocessor from a single source file (e.g. main.cpp).

The compiler generates an object file (main.obj).

The linker combines all necessary object files and libraries together to create
an executable program. More on the libraries later.

26
Debugging

27
Debugging:Diagnostic Messages
Sometimes, to debug your program, you will include some diagnostic
messages:
e.g.
void PrintNormalized(...) {
...
//See if all is correct
for (i=0; i < 26; i++)
cout << counter[i];

28
Debugging
- When you think you are done debugging, you can do one of the followings to turn
debug statements off (so that your program runs fast and without debug
messages of course)
1) remove all this debug code (e.g. cout’s)
• Too much work, plus you may need them again when some other problem shows
up (if you need debugging later on)

2) make them conditional to a program variable. For instance:


if (debug == 1) {
for (i=0; i < 26; i++)
cout << counter[i];
}

- Then by setting the variable debug to 1 or 0 on top of the program, or when you call
the program, you can control whether the statements will be output.
- Tests such as “if (debug)” are still done (slows the release version)!
- However this type of debug messages has the advantage that they are interactive. In
other words you can run your big project and start testing several aspects and you
can have an option of receiving the debug variable from the user (or several debug
variables) as a parameter and interactively start/stop outputting diagnostic
messages, without recompiling your code. This may come in handy only for some
big, interactif projects.

29
Debugging
3) or similarly you can turn them off. For instance:
• if (0){
for (i=0; i < 26; i++)
cout << counter[i];
}

-
4) Best: include debugging code with preprocessor directives that are defined on top of
the program or specified by Proj./Settings....

#ifdef _DEBUG
for (i=0; i < 26; i++)
cout << counter[i];
#endif

30
Debugging:Debug/Release
You will normally develop under debug mode (configuration), test, then
release (optimized)
– When you are developing with Debug option, the compiler keeps track of
symbolic information so that you can watch over variable values, function call
hierarchy etc., at every step in your code.

– Once you are done debugging and you will release the code to the customer
(or teacher), you want to remove this information and any other debugging
code you may have added so that your executable is cleaner, smaller and
faster.

– In VC 6.0 You can set the “active configuration” from:


Project/Settings
Build/Set Active Configuration
Choose Debug mode or Optimize (Release mode)

31
Debugging:Debug/Release
– In VC 6.0 You can set the “active configuration” from:
Project/Settings
Build/Set Active Configuration
Choose Debug mode or Optimize (Release mode)

– In VS 2008, select from the Build tab, then from Configuration Manager (see
the next screenshot)

32
33
Preprocessor Directives Under Debug Setting

34
Preprocessor Directives Under Release Setting

35
Debugging
#ifdef _DEBUG
for (i=0; i < 26; i++)
cout << counter[i];
#endif

– This code will only be compiled if the _DEBUG flag is set during compilation

• _DEBUG is a standard preprocessor directive which is defined in the DEBUG


configuration, but not defined in the Release configuration.

• So when the preprocessor parses your code:

- if the _DEBUG prep. directive is defined, it will remove the #ifdef


commands and include the lines between them (cout << p->Info;)
in your program.

- if the _DEBUG prep. directive is NOT defined, the preprocessor


will remove the #ifdef commands AND the lines between them
(cout << p->Info;) out of your program. So your program will be
as if you have never written those lines (no extra tests done etc.)

38
Debugging
You can also use your own preprocessor directives:
– You can either add them to the preprocessor directives under Project/Settings/... As
_DEBUG was defined
– Or you can define them with “#define SHORTDBG” etc. in the beginning of the file
//You can define or not define your debug flags:
#define SHORTDBG
//#define MAJORDBG
...

#ifdef SHORTDBG
cout << “*** Value of num = “ << num << endl;
#endif

#ifdef MAJORDBG
cout << “*** Value of num = “ << num << endl;
cout << “*** Value of info = “ << info << endl;
cout << “*** Value of t = “ << t << endl;
...
#endif
39
Debugging
- Best: you can also make them conditioned on the automatic flag
_DEBUG:

#ifdef _DEBUG
#define SHORTDBG //this code won’t be compiled under release config

//#define MAJORBG //this code won’t be compiled under release config

#endif

This way, if you are running under the release config., you don’t need to turn
SHORTDBG or MAJORDBG off. Since their definition won’t even be compiled,
your flags won’t be defined.

40
Preprocessor Output: debug version
n = 1; n = 1;

#ifdef _DEBUG
cout << n; cout << n;
#endif

DoSmthg(); DoSmthg();
DoSmthgElse(); DoSmthgElse();

_DEBUG is defined as a preprocessor directive under the Debug


build of your code.

41
Preprocessor Output: release version
n = 1; n = 1;

#ifdef _DEBUG
cout << n;
#endif

DoSmthg(); DoSmthg();
DoSmthgElse(); DoSmthgElse();

_DEBUG is not defined as a preprocessor directive under the


release build of your code.

42
Debugging: Assert statements
- Use assert statements to check for conditions that should be true (e.g.
preconditions/postconditions of a function)

#include <cassert> //where assert is defined


...
assert (p != NULL); //any Boolean expression
...

assert ( i < j );

If the inside expression evaluates to true, execution continues.


If the inside expression evaluates to false, execution is halted (program aborts).
A message is dumped at this point, something along the lines of :

• assert ( i < j ) at line 543 of file code.c failed

43
Debugging
Assert statements
- assert statement should not replace checking and handling errors (e.g. if
the file is found or not)

- provides compact checks for things that should not happen (e.g. would
cause the program crash)

- What to do (free variables etc.) when this happens?


– We will see exception handling in the coming weeks for a neat organization of
error handling

44
Debugging
Assert statements
- The assert statement can be "turned off" by defining the preprocessor
directive NDEBUG before including “cassert":

#define NDEBUG // “No Debug”


#include <cassert>

- If you use the release configuration, NDBUG is already defined, so you


dont need to define it yourself.

45
Debugging
Assert statements - Advanced
- The assert statement can be "turned off" in the final build by defining NDEBUG
before including “cassert":

//NDEBUG defined by configuration or by you


#include <cassert>

In cassert, NDEBUG preprocessor directive is checked:

– If it is defined, the assert statement evaluates to an empty statement, which is what


we want for the Release version, so the tests do not slow the program and things that
may not cause a crash is not unnecessarily reported to the customer.

– If it is not defined (Debug mode), the assert statements stay and do the tests as
intended.

47
assert.h - Advanced
...
#ifdef NDEBUG

#define assert(exp) ((void)0) //define it to be empty

#else
...

#define assert(exp) (void) ( (exp) || (_assert(#exp, __FILE__, __LINE__), 0) )

#endif /* NDEBUG */

Note: In this and the next 2 slides, you dont need to understand how this code works
exactly; but understand the idea of how NDEBUG is checked and used in assert.h
(called by cassert).

48
Preprocessor Output: debug version
Advanced
n = 1; n = 1;

#ifdef _DEBUG
cout << n; cout << n;
#endif

DoSmthg(); DoSmthg();
DoSmthgElse(); DoSmthgElse();

assert(exp); (void) ( (exp) || (_assert(#exp, __FILE__, __LINE__), 0);


//either expression is true or the next statement runs and succeeds
(returns true)
n++;
n++;

49
Preprocessor Output: release version
Advanced
n = 1; n = 1;

#ifdef _DEBUG
cout << n;
#endif

DoSmthg(); DoSmthg();
DoSmthgElse(); DoSmthgElse();

assert(exp); void(0);

n++; n++;

50
Debugging: Example under Week1/
#include <iostream>
#include <cassert>
using namespace std;

/***********************************************************
This program shows various debug alternatives that students can
play with.
Author: Berrin Yanikoglu
Date: 24/2/2005
Bugs: No known
************************************************************/

/***********************************************************/
// a function you received from a colleague, you don't know
//fully what it does
/***********************************************************/

void func1(int & n) {


n = 1;
}

51
/***********************************************************/
//main function
/***********************************************************/
void main()
{

char c; //to receive user input


int count = 0;

#ifdef _DEBUG
//this code will be executed under the DEBUG config. only
#define DEBUG1 //less detailed debugging
#define DEBUG2 //more detailed debugging
#endif

#ifdef DEBUG1
//this code will be executed under the DEBUG config. only
cout << "debugging comment conditioned on DEBUG1" << endl;
#endif

func1(count);

#ifdef DEBUG2
//this code will be executed if DEBUG2 is defined
cout << "debugging comment conditioned on DEBUG2"<< endl;
cout << count;
#endif

assert(count == 0);

cout << "Press any key to continue";


cin >> c;

52
Preprocessor, Compiler, Linker ctd.

Horton Chp. 1

PDF version
Web notes

53
Header Guards
A very important use of conditional compilation is to prevent multiple
inclusion of header files. (Multiple inclusion would duplicate
declarations, resulting in compiler errors.)

In the following example, _DICE_H is defined when ”dice.h” is included the first
time, hence later inclusions of ”dice.h” won’t have any effect on translation.

#ifndef _DICE_H
#define _DICE_H

….

….

#endif

54
Macros
The #define directive is also used to define macros with
parameters:

#define SQUARE(x) x*x

After this macro definition, the preprocessor will replace any text in
the form SQUARE(something) with something*something.

This macro is supposed to define a squaring operation without


writing a real C++ function. But it is wrong!

55
#define SQUARE(x) x*x

56
#define SQUARE(x) x*x

57
58
Linker
Combines all necessary object files and libraries together to create an
executable program.

Some of the object files may be combined together to form libraries.


– It is very advantageous to use libraries as they are pre-tested code

Making libraries of your class:


– e.g. taps.lib

59
Misc.: libraries
Creating a statically linked library:
– choose your project as “statically linked library”,
as opposed to a “console application”
– Add the files you want to use (Project/Add File/…
• E.g. Date.c date.h
– No main function
– Build – the output is a lib file, e.g. taps.lib

Using this library:


– Create your project (e.g. hw0) that will use this library
– Add a main file etc (that does the work)
– Add the library as another file to the project (Project/Add File…)
– Compile
– It is just as adding dice.cpp etc. To the project, but in one easy step.

You may create a static versus dynamic library, in general. But we deal with only
statically linked libraries for now.

60
Static versus Dynamic (shared) Libraries

The libraries you link statically are linked into the final executable by the
linker (remember that they are pre- compiled).

Dynamic libraries are libraries that have the library name embedded into the
executable but the library itself is not linked to the final executable.
When you compile a program, the linker verifies that all the symbols
(functions, variables …) required by the program, are either linked into
the program, or in one of its shared libraries. However, the object files
from the dynamic library are not inserted into the executable file.

Instead, when your program is started, a program in the system (called a


dynamic loader) checks out which shared libraries were linked with the
program, loads them to memory, and attaches them to the copy of your
program in memory.
61
Advantages and Disadvantages of
Dynamic (shared) Libraries
Advantages:
– Since the library is not compiled into the executable the executables tend
to be smaller.
– If you have a lot of programs that utilize the same library
– you might be able to save considerable disk space
– you only need to upgrade the library and then all the programs that use it go
on as if nothing has changed
– If the name of the library changes you can just create a symbolic link to
the old library name and your code works just fine.

Disadvantages:
– Launching your program (the one that uses the library) is a bit –
insignificantly – slower
– If the library is somehow lost/corrupt etc, your executable will not work.
62
Dynamic (shared) Libraries: Reference
Shared libraries are linked into the program in two stages. First, during compile
time, the linker verifies that all the symbols (again, functions, variables and the
like) required by the program, are either linked into the program, or in one of its
shared libraries. However, the object files from the dynamic library are not
inserted into the executable file. Instead, when the program is started, a program
in the system (called a dynamic loader) checks out which shared libraries were
linked with the program, loads them to memory, and attaches them to the copy of
the program in memory.

(Dis)Advantages: The complex phase of dynamic loading makes launching the


program slightly slower, but this is a very insignificant drawback, that is out-
weighted by a great advantage - if a second program linked with the same shared
library is executed, it can use the same copy of the shared library, thus saving a
lot of memory. For example, the standard "C" library is normally a shared library,
and is used by all C programs. Yet, only one copy of the library is stored in
memory at any given time. This means we can use far less memory to run our
programs, and the executable files are much smaller, thus saving a lot of disk
space as well.

Advanced Note: there is one drawback to this arrangement. If we re-compile the dynamic library and try to
run a second copy of our program with the new library, we'll soon get stuck - the dynamic loader will find
that a copy of the library is already stored in memory, and thus will attach it to our program, and not load
the new (modified) version from disk. There are ways around this too.
63
Miscellaneous Info
Debugging:
VC++ environment
Read VC++help.doc for some more and go to recitations for more info and practice
on these.
– Set a breakpoint
• F9 or Edit/Breakpoints
– Run until next breakpoint
• F5
– Step in: F11
– Step out: Shift-F11
– Step over: F10
– Run to cursor: Ctrl-F10
• (see the MSDN library for more details)

– Inspecting variables:
• Variables window
• Watch window
• Quick watch
• Cursor over text
• Call stack

65
Debugging:Project Options
- Setting Include and Source Directories
– You can specify where the compiler should look for include files by:
• Tools/Options/Dirs/Source Files
Specify where the .h and .cpp files should be looked under
Put it at the end so your include files dont get prefered over system’s

- However, make sure that when you submit your code, you have all the necessary
files under the project directory!
• if you set the include directory location, many include files will be found under some directory,
(e.g. C:/Courses/CS201/Code/) when you develop your project under another directory (e.g.
C:/Courses/CS204/projects/pointers/). This has the drawback that when you submit your code,
these files will not be in the local directory and added to the zip.

• In order to avoid this, you can look at each file (right click, and properties) to see where they
are brought from, or you can make sure you have a local copy under that project folder, or you
can test your homework submission on a separate computer etc.

Your submitted project must open, find all necessary files, and build with a few clicks!

66
Misc.: redirecting input/output
Directing standard output
– Program/Settings/Debug
• > ./filename
– The output will go to the file (cout << statements), so you don’t have to cut
and paste from the console.

Passing arguments to the program


– Program/Settings/Debug
• < ./inputA.txt 2
– The “inputA.txt” and “2” (in general, any parameters that you want to use while
calling your program) will be passed in argv to the main function (as in hw1).

67
How to Redirect Output
Right click on Project, choose properties, Debugging properties under
Configuration Properties. Add “>out.txt” to Command Arguments to
redirect Standard output that normally goes to the DOS window
(black) to out.txt in Project directory, as shown below (see Fig. 5)
Fig.5. How to redirect output in VS 2008.

68
69

You might also like