- Forward


Developing in C/C++
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu

Print

Applications in C/C++
Back SMYC Forward
  • Applications Usually Consist Of:
    • One or more "modules" written by "you"
    • One or more libraries (written by "somebody else")
  • "Your" Modules Usually Consist Of:
    • One or more header files (containing declarations/specifications)
    • One or more source files (containing definitions/implementations)
Overview of the Development Process
Back SMYC Forward
cpp_development-process

A Note for Java Programmers: Java does not have a linker and does not (normally) produce executable files. Instead, the compiler creates byte code that is executed by an interpreter.

The Preprocessor
Back SMYC Forward
  • The Sequence:
    • The preprocessor is run on source and header files before they are passed to the compiler
    • The preprocessor is often invoked automatically by the compiler
  • Syntax:
    • Preprocessor statements are not written in C/C++; they have a completely different syntax
    • All preprocessor statements must begin in the first column
The Preprocessor - Text Replacement
Back SMYC Forward
  • Motivation:
    • It is sometimes convenient to replace one piece of text with another just before compiling a source file (e.g., to define constants)
  • Syntax Click here for information. :
    • #define original_text substitute_text
    • Note: There is a parameterized version of the #define statement that can be used for more complicated substitutions. It is best to avoid the use of "macros" of this kind.
  • Description:
    • The preprocessor (temporarily) replaces all occurrences of original_text with substitute_text
    • original_text must be a single "word" (i.e., must not contain any white space
    • substitute_text can be virtually anything
The Preprocessor - Conditional Compilation
Back SMYC Forward
  • Motivation:
    • You sometimes want to compile a source file differently in diffierent situations (e.g., to switch between a "verbose" version of a program that includes a lot of output statements for debugging and a "quiet" or "terse" version of the same program)
  • Syntax Click here for information. :
    • #ifdef symbol
      statement...
      #endif

      where statement is valid C++ code or a preprocessor statement
  • Description:
    • The C/C++ code will be compiled if symbol is defined and will not be compiled otherwise
    • A symbol is defined using the #define statement (e.g., #define VERBOSE) and is undefined using the #undef statement (e.g.,#undef VERBOSE)
The Preprocessor - Conditional Compilation (cont.)
Back SMYC Forward

An Example

#ifdef VERBOSE cout << "Inside factorial: n = " << n << "\n"; #endif
The Preprocessor - Conditional Compilation (cont.)
Back SMYC Forward
  • Command Line Switches:
    • Most compilers/preprocessors enable you to define/undefine symbols at the command line
    • This is often accomplished using the -D option
  • Also of Note:
    • The preprocessor also recognizes the #ifndef statement (if not defined) and the #else statement
The Preprocessor - Including Other Files
Back SMYC Forward
  • Motivation:
    • C/C++ programmers often want to use the same variable declarations in more than one file. One way to do this is to put the declarations in one file and temporarily "copy" this file into the other files.
  • Including Standard Header Files:
    • #include <filename>
  • Including "Local" Files:
    • #include "filename"
The Preprocessor - Including Other Files (cont.)
Back SMYC Forward
  • An Observation:
    • The same file/class might be used by multiple files/classes and so will appear in multiple #include statements
  • Another Observation:
    • #include statements can be nested (e.g., the file test.cpp can #include test.h and test.h can #include myconstants.h)
    • This is very convenient but can make it difficult to identify all of the files that are included
  • The Problem:
    • The compiler does not allow things to be defined more than once
  • Fixing this Problem:
    • It is good practice to use conditional compilation with #include statements
The Preprocessor - Including Other Files (cont.)
Back SMYC Forward

Account.h

#ifndef Account_h #define Account_h . . . #endif
The Preprocessor - Including Other Files (cont.)
Back SMYC Forward
  • Some Observations:
    • You may want to use code that was written by somebody else
    • They might have used the same symbols you used
  • A Solution:
    • Use symbols that uniquely identify your code (e.g., include your organization and user ID in the symbols)
The Preprocessor - Including Other Files (cont.)
Back SMYC Forward

Account.h

#ifndef edu_jmu_cs_bernstdh_Account_h #define edu_jmu_cs_bernstdh_Account_h . . . #endif
The Preprocessor - Including Other Files (cont.)
Back SMYC Forward
  • A Question:
    • Should I #include unrelated files in the .h file or the .cpp file?
  • The Consensus Opinion:
    • Yeah, right!
  • My Opinion:
    • Choose the "most local" alternative (e.g., if it is needed for declarations then #include it in the .h file whereas if it is needed only for implementation then #include it in the .cpp file)
The Compiler
Back SMYC Forward
  • Purpose:
    • Translates source code (in this case written in C++) into what is usually called object code (or machine code)
  • Steps:
    Lexical Analysis Identification of tokens (e.g., keywords, identifiers, etc...) (this process is sometimes called scanning)
    Syntactic Analysis Identification of grammatical and ungrammatical phrases. (this process is called parsing)
    Code Generation Production of object or machine code (or some kind of intermediate code) from the "parse tree"
    Optimization Improvement of code to make it smaller or faster (or to achieve some other objective)
The Compiler (cont.)
Back SMYC Forward
  • Error Messages:
    • Error messages are "fatal", that is, they are generated by mistakes that prevent the compiler from generating object code
  • Warning Messages:
    • Warning messages advise you of things that you are doing that you may not be aware of (which may prevent your code from executing correctly)
  • A Note for Java Programmers:
    • C/C++ compilers are typically much more forgiving than Java compilers
The Linker
Back SMYC Forward
  • Purpose:
    • Most applications start out as several "pieces" that need to be "glued together"
  • A Note for Java Programmers:
    • The Java interpreter uses a class loader that automatically "glues the pieces together"
The Linker (cont.)
Back SMYC Forward
  • The Compiler and the Pieces:
    • The compiler doesn't actually need access to all of the pieces, it only needs to know about them
    • For example, when a module uses an external sqrt function, the compiler only needs to know the signature of this function (e.g., what it is passed and what it returns)
    • The information needed by the compiler is normally contained in header files (which are made available to the compiler using the #include directive)
  • The Linker and the Pieces:
    • To execute a program, the actual method/function needs to be available
    • Hence, the linker has to resolve all of these references and relocate all of the object modules relative to the start of the complete application. (This process is called static linking. It is also possible to defer some linking until execution. This is called dynamic linking and is beyond the scope of this course.)
    • Linkers can generate both error and warning messages (the most common errors involve references that cannot be resolved because the linker does not have access to all of the "pieces")
Executing/Running a Program
Back SMYC Forward
  • An Explanation:
    • The executable code that is produced by the linker uses relocatable addresses so that it can be run in different memory locations
    • The loader identifies a memory location in which an application can be loaded and alters the relocatable machine code addresses to run in the designated memory location
    • Most applications are loaded into memory each time they are run
  • The Process:
    • In general, you run an application by entering its name at the command line or "clicking on" its name/icon
Practical Issues
Back SMYC Forward
  • Development Environments:
    • Some people prefer Integrated Development Environments (IDEs) that provide access to and integrate an editor, compiler, linker, and debugger.
    • Other people prefer to work from a command shell that doesn't integrate the various tools
  • Managing the Process:
    • Regardless of the environment, most people use a make/build utility, a tool that automates the building of complex applications.
There's Always More to Learn
Back -