Fequently Asked Questions

  1. Emacs Braces Indent How do I fix emacs so that braces are not indented in my code?
  2. gcc/g++ Error Message Display How do I make the gcc/g++ error messages display quotes correctly?
  3. SPAM How can I slow down the spam onslought?
  4. Elm "two copies" Error" I get the message from elm that I seem to be already running a copy of elm, but I am not. How do I fix this?
  5. Emacs - getting started I am lost with regards to emacs. I have been reading through the tutorials and it makes little to no sense to me. I like to think I am fairly handy with the computer, but I can not see how to even get emacs to create files. Unless for whatever reason it is not running correctly on my machine, I am stuck. Please help.
  6. std::endl What is the difference between std::endl and '\n'?
  7. Explain "size_t" : What kind of entity (variable, type, ...) is "size_t"? Where is it defined? Where do we use it? Why is it better to use it?
  8. Const The C++ const modifier: What is the point to using it?
  9. Multiple Read Protection [#ifndef - 1] When creating header files, what is the #ifndef ... #define ... #endif for, why do we need it, and how does it work?
  10. Multiple Read Protection [#ifndef - 2] What if we have, say, 4 class headers being stored in one file, for convenience. Would we use ONE #ifndef directive or MULTIPLE #ifndef directives around each individual class header?
  11. Killing Background Processes How can I "get a handle" on old background processes? How do I clean them up?
  12. ^Z , ^D , and background processes Explain the Unix control signals ^Z and ^D? (using '^' to mean the control key)
  13. Compile Error Messages When I try to compile, I get a lot of error messages that I don't understand. In fact, I find them intimidating! Where are they coming from?
  14. Undefined or multiply defined symbols I am getting errors about undefined or multiply defined symbols. Where are these coming from, and how do I correct them?
  15. Undefined or multiply defined references I am getting errors about undefined or multiply defined references. Where are these coming from, and how do I correct them?
  16. Best Practices: Scope of Declared Constants I take it that declared global constants are acceptable provided that they are useful across multiple scopes. For example, when defining an upper bound on an array that will be passed among several functions or used across different scopes. Would it be safe to say that constants should be defined over the smallest scope possible?
  17. Best Practices: Scope of Variables What is the convention (for declaring variables) in C++? Is it moving toward limited scope declarations or is it keeping to the function level scope of C?
  18. Return by Reference - 1. In certain situations, such as assignment operators, bracket operators, and I/O operators, the return type is a reference. What does this mean, and how do we handle it in the implementation?
  19. Return by Reference - 2. OK, I tried to return something by reference and got a compile error. When I changed to return by value, it worked fine. What gives? Any special rules at work here?
  20. Explicit The explicit keyword: What is the purpose of using explicit in front of a constructor?
  21. Include File Notation What is the difference between #include"file" and #include<file>, and why is the latter one preferred?
  22. Best Practices: Include Files What is the best practice for #include notation, and why?
  23. Virtual Method Tables How are virtual method calls implemented?
  24. Spell Checker Is there a Unix/Linux spell checker?
  25. Alias How can I create simple command abbreviations?
  26. ssh How can I invoke commands like "elm" on shell from linprog?

Fequently Asked Questions with Answers


Question: How do I fix emacs so that braces are not indented in my code?

Answer: This is in regards to the indentation of the block braces to the control statements. The default seems to be to have extra indentation from the column where the control statement is to where the block goes. For example:

int main()
{
  for( ;; )
    {
      // code...
    }
}

You can add the line:

(c-set-offset 'substatement-open '0)  

to your emacs init file to make the indentation like this:

int main()
{
  for( ;; )
  {
    // code
  }
}

You can add this to your .emacs file, but even better you can create your own personal emacs init file (you call it ".emacs_LOGINNAME_init" and put it in your home folder. (Mine is .emacs_lacher_init.) Then you need to edit your ~/.lisp/startup.el file. Look for the lines:

;; Read more personal initial init-file, if possible.                           
;(load (concat "~/.emacs_" (user-login-name) "_init") t) 

and just uncomment the line that loads the file.
(Back to FAQs)


Question: How do I make the gcc/g++ error messages display quotes correctly?

Answer: Edit your system file ".tcshrc" by adding one line:

setenv LC_ALL C

Be sure to use emacs or vi, and be careful not to mess with anything else in the file. Add the line immediately after the other lines that begin with "setenv".
(Back to FAQs)


Question: How can I slow down the spam?

Answer: There is no perfect solution to the spam problem, that is, no solution that stops all unwanted email without also stopping some you want, or vice versa. But at the user level, you can prefilter most of the spam into a folder, which you can check occasionally and remove.

Here is a sample procmail script for user-level spam control. This script should be the contents of a file named ".procmailrc" in your home directory. Mine seems to work with permissions set to 600. Please note:

CAUTION: Use at your own risk, and test to be sure it works!

Here is the script (use TAB to indent the commands):

SHELL = /bin/sh
LOGFILE=$HOME/Mail/log
MAILDIR=$HOME/Mail
#INCLUDERC=$HOME/rc.mail
:0:
     *!From:.*\.cs\.fsu\.edu*
     SPAM

This should send any email that does not have ".cs.fsu.edu" in its "from" field to a folder named "SPAM". You can check and/or remove this folder periodically. (It's really just a file that is processed as a folder by elm.)

To check email stored in a folder, use the command "elm -f [folder]".


(Back to FAQs)


Question: Elm "two copies" Error" I get the message from elm that I seem to be already running a copy of elm, but I am not. How do I fix this?

Answer: If you have killed elm or otherwise exited from elm in an unexpected manner, the working elm scratch file will still exist. This is a file whose exact name and location are part of the message sent when you try unsuccessfully to invoke elm. Simple "rm [filespec]" gets rid of this file, and then elm should work OK.

It's not a good idea to mix mailers, swapping back and forth between elm and pine, for example. You may end up losing or mis-filing some mail.

Here is a screen shot, with user input shown in color:

lacher@diablo:~> elm
...
You seem to have ELM already reading this mail!
You may not have two copies of ELM running simultaneously.
If this is in error, then you'll need to remove the following file:
 /tmp/mbox.lacher.lacher
lacher@diablo:~> ps -ulacher
 PID TTY TIME CMD
 23653 ? 0:03 elm
 19592 pts/28 0:00 ps
 19534 pts/28 0:00 tcsh
 19532 ? 0:00 sshd
lacher@diablo:~> kill 23653

Elm is now freed up, because it deletes the scratch file as it exits. Another case is illustrated by this shot:

lacher@diablo:~> elm
...
You seem to have ELM already reading this mail!
You may not have two copies of ELM running simultaneously.
If this is in error, then you'll need to remove the following file:
 /tmp/mbox.lacher.lacher
lacher@diablo:~> ps -ulacher
 PID TTY TIME CMD
 19592 pts/28 0:00 ps
 19534 pts/28 0:00 tcsh
 19532 ? 0:00 sshd
lacher@diablo:~> rm /tmp/mbox.lacher.lacher

Note that elm is not actually running, so we fixed by deleting the scratch file. This happens often enough that I made an alias "elmfix" that deletes the file. (To make an alias, just enter "ea".)
(Back to FAQs)


Question: I am lost with regards to emacs. I have been reading through the tutorials and it makes little to no sense to me. I like to think I am fairly handy with the computer, but I can not see how to even get emacs to create files. Unless for whatever reason it is not running correctly on my machine, I am stuck. Please help.

Answer: Just learn how to get started. First, know what the genera is: a text editor (not a wordprocessor), intended to be used in creating and modifying text files.

To start emacs with a file "myFile", enter the command:

emacs -nw myFile

This will open an editing session in your terminal window. If myFile already exists (in the directory your are in) emacs will read the file into the editor as it starts up. Otherwise myFile will be created.

Once you have the file open, take a look at the info lines at the bottom of the emacs screen. These tell you what file you are editing, line number of the cursor, and other stuff. Commands that need a parameter will prompt you for it down here. Now when you type stuff it appears in the window. If you have copied the emacs setup files correctly, the backspace and arrow keys should work appropriately.

When finished, type

Ctrl-X Ctrl-S (to save the file)
Ctrl-X Ctrl-C (to quit emacs)

Other edit features:

Ctrl-K     ("kill" - deletes from cursor to end of line and puts in kill buffer)
Ctrl-Y     ("yank" - inserts contents of kill buffer at cursor)
Ctrl-Space (sets mark at cursor)
Ctrl_X Ctrl-X (exchange mark and cursor)
Ctrl-W     ("write" - deletes from mark to cursor and puts in kill buffer)

Note that the kill buffer accumulates during a series of Ctrl-K, but if any other keystroke intervenes between then Ctrl-K and Ctrl-W overwrite whatever was in the kill buffer. Thus:

Ctrl-K Ctrl-K Ctrl-K Ctrl-K

has the effect of putting two lines together with their end of line characters in the kill buffer.

Note that when editing a C++ file, the TAB key is an auto-formater: hit TAB anywhere on a line and that line indents according to a specific coding style. However when editing a makefile, TAB inserts a TAB at the cursor. A few other handy features when editing/debugging programs:

Ctrl-C Ctrl-G <number><Enter>  (go to line number)
Ctrl-X i  <file>          (insert contents of file at cursor)
Ctrl-X Ctrl-F <file> (read file)
Ctrl-A   (beginning of line)
Ctrl-E   (end of line)
Ctrl-S   (forward search)
Ctrl-R   (reverse search)
Esc-%    (search and replace)

This is enough to get started and be effective editing programs and makefiles.
(Back to FAQs)


Question: std::endl What is the difference between std::endl and '\n'?

Answer: What's actually happening is that there is a manipulator std::flush that forces the clearing of the stream buffer, which in turn forces the operating system to send the output immediately. Then std::endl is defined to insert the newline character '\n' and then call std::flush.

It is in fact good practice NOT to use std::endl. In almost all circumstances, your code runs better if you let the OS decide when to clear buffers. Just insert the newline character when you want a line break. Then, when you really, really need to force a buffer flush, call std::flush.

Forced buffer flush is almost never needed, because std::cout and std::cin are tied streams, so that std::cout will automatically flush prior to any use of std::cin, and because std::cerr is not buffered at all, so std::flush has no effect on it anyway.
(Back to FAQs)


Question: Explain "size_t": What kind of entity (variable, type, ...) is "size_t"? Where is it defined? Where do we use it? Why is it better to use it?

Answer: size_t is an unsigned integer type defined in stdlib.h. (Note this is a type, not a value.)

The mechanism for defining a type uses the keyword "typedef", like this:

typedef unsigned int size_t;

size_t defines the range for "size" variables, such as array index variables, allowed by the compiler. The size of this range is not part of the C++ language specification, and may vary among all of the 4 possibilities [char, short, int, long], depending on the particular platform:

typedef unsigned char size_t;   // 1 byte range: [0..255 = 2^8-1]
typedef unsigned short size_t;  // 2 byte range: [0..65535 = 2^16-1]
typedef unsigned int size_t;    // 4 byte range: [0..4294967295 = 2^32-1]
typedef unsigned long size_t;   // 8 byte range: [0..18446744073709551615 = 2^64-1]

All of these are realistic possibilities. Compilers set up to target embedded systems often restrict sizes to something much smaller than 8 bytes.

Here are the sizes of unsigned types for g++ on 64-bit Intel:

Size of unsigned char  = 1 bytes
Size of unsigned short = 2 bytes
Size of unsigned int   = 4 bytes
Size of unsigned long  = 8 bytes
Size of size_t         = 8 bytes

and for g++ on 32-bit Intel:

Size of unsigned char  = 1 bytes
Size of unsigned short = 2 bytes
Size of unsigned int   = 4 bytes
Size of unsigned long  = 4 bytes
Size of size_t         = 4 bytes

Using size_t in your source code makes it more portable from one platform to another. For more on this, see the article Why size_t matters by Dan Saks on Embedded.com.
(Back to FAQs)


Question: The C++ const modifier: What is the point to using it?

Answer: The modifier "const" is an important part of C++. It has "context-dependent sematics" (i.e., what it means varies with context).

  1. For pointers: there are two different things that can be held constant - the variable itself and the thing the variable points to. Either or both of these can be designated in a declaration by using the modifier "const". Here are three examples:
    const char * name;       // holds values constant
    char * name const;       // holds variable constant
    const char * name const; // holds both constant
    
    The first makes sure that the values pointed to are held constant. This is a string whose characters are not allowed to be changed. The second holds the variable "name" constant but allows the values pointed to to be changed. The third holds both the variable and what it points to constant. Note that the second example is the one that behaves like a typical array.
  2. These may be invoked for an existing pointer in a specific scope, for example during a function call. If you have a pointer to something and you want to change that something in a client program but ensure that no changes are made by a function call, then you put the const modifier in the function prototype, as in:
    void Func ( const char* n )
    
    This will ensure that a call such as Func(name) will not change the elements of the array name during the call.
  3. Similar discussion pertains to references.
  4. Recap by example of legal / illegal function calls:

    no const modifiers:
    void Func ( char* n );       // prototype of Func
    char * name;                 // declaration of variable in main()
    ...                          // code to modify characters of name
    Func(n);   // legal call - function call allowed to change characters of name
    
    non-const passed as const:
    void Func ( const char* n ); // prototype of Func
    char * name;                 // declaration of variable in main()
    ...                          // code to modify characters of name
    Func(n);   // legal call - guaranteed not change characters of name
    
    const passed as const:
    void Func ( const char* n ); // prototype of Func
    const char * name;           // declaration of variable in main()
    ...                          // characters of name cannot be changed
    Func(n);   // legal call - guaranteed not change characters of name
    
    const passed as non-const:
    void Func ( char* n ); // prototype of Func
    const char * name;     // declaration of variable in main()
    ...                    // characters of name cannot be changed
    Func(n);   // ILLEGAL call - cannot pass const to non-const
    

(Back to FAQs)


Question: Multiple Read Protection [#ifndef - 1] When creating header files, what is the #ifndef ... #define ... #endif for, why do we need it, and how does it work?

Answer: This is the accepted practice, inherited from C, that prevents multiple reads of a file. It can and should be applied to any file that may be used as an "#include" file in other code. In C++ it is used to protect header files (function prototypes and/or class definitions) as well as template files.

The reason such protection is needed: C and C++ compilers do not like to see something defined twice. The compilers are not smart enough to decide whether multiple definitions are equivalent, therefore they just refuse to proceed when a second definition for the same entity is encountered. (The same is true for linkers, but that is another story.) Here is a layout of this technique in use:

/*  file:    myfile.h 

    contains definition of class MyClass
*/

#ifndef _MYFILE_H    /* 1 */
#define _MYFILE_H 1  /* 2 */
...
namespace myStuff
{
  ...
  class MyClass
  {
    // class methods and variables
  };
  ...
} // namespace myStuff
...
#endif               /* 3 */

The way this works: The compiler builds a symbol table of names of functions, classes, variables, etc, that are defined in a program. The #ifndef _MYFILE_H statement at line marker /* 1 */ directs a lookup of the symbol _MYFILE_H in this table and proceeds when that symbol is not found. The #define _MYFILE_H 1 at /* 2 */ puts the symbol into the table, so that it will be there the next time an inquiry is made. The #endif statement at marker /* 3 */ delimits the end of the #ifndef block. In the example above, the symbol "_MYFILE_H" is given the definition "1". It is also legal to omit any actual definition for the symbol, in which case it is entered into the table with "the empty meaning".

Note that all of this is being handled by the preprocessor, which is a kind of automated text editor. Also note that the symbol table is used only during compilation, it is not part of the execution environment, so this process does not add overhead to the executable.

Also note that _MYFILE_H is a legal C++ identifier. The actual file name is not a legal C++ identifier because it contains the "dot". Any legal identifier may be used. It is common practice to build an identifier from the file name with some sort of "morph" algorithm that produces a name that is unlikely to be used as an identifier in a program, thus preventing name clashes which would be caught by the compiler. The leading "_" also serves to make the file protection identifier unlikely to be used as an identifier in a program.

Finally, note that this file protection identifier is a morph of the file name, not the namespace name or the class name.

The bottom line: you can safely include (protected) header files where they are needed without worrying about the order they will be read in a project build. The protection guarantees that whenever the first include statement is encountered, the file will be read, the "symbol" will be defined, and all subsequent encounters will be bypassed.
(Back to FAQs)


Question: Multiple Read Protection [#ifndef - 2] What if we have, say, 4 class headers being stored in one file, for convenience. Would we use ONE #ifndef directive or MULTIPLE #ifndef directives around each individual class header?

You would just protect the whole file. The purpose of a header file inclusion is to supply defintions of classes or functions to a client program. This does not "bulk up" the executable, it just provides information used in the compile process. Thus there is no harm in over-supplying definitions.

Of course, you could go overboard with this, throwing hundreds of class defintions into one file, then the compile process would get noticably slowed by packing the (temporary) symbol table with unneeded terms. Good design will prevent such excesses by having only a collection of related classes defined in the same file.

Answer:
(Back to FAQs)


Question: Killing Background Processes: How can I "get a handle" on old background processes? How do I clean them up?

Answer: If you have accidently left elm (or any other program) running in the background, you need to kill the process. First find out what you have running with the command:

ps -u[username]

This will list your currently running processes. Then the command

kill [number]

will take out any process you don't want running. The number is listed by the ps command.
(Back to FAQs)


Question: Explain the Unix control signals ^Z and ^D? (using '^' to mean the control key)

Answer: In Unix/Linux, keyboard ^D sends EOF and ^Z is a STOP signal. (MS Windows uses ^Z as EOF.)

^D at the command prompt is often interpreted as a logout signal. In standard input to an executing program, ^D sends the end of input signal, simulating the end of data in a file.

^Z in emacs sends the job to background. Background jobs can be returned to forground by first entering "jobs" and then "fg [job#]" to bring to forground. You can also use "bg [job#]" to send a running job to background. Background is a good category to use for executing programs that will run a long time, because it sets priority low enough not to interfere with other users' forground jobs.
(Back to FAQs)


Question: Compile Error Messages: When I try to compile, I get a lot of error messages that I don't understand. In fact, I find them intimidating! Where are they coming from?

Answer: If you consider the various things that can go wrong between typing the "make" command for a program and running the resulting executable, it is a wonder that it ever works! Error messages can come from:

Can you explain what's wrong with this code?
Back to FAQs


Question: Undefined or multiply defined symbols / references: I am getting errors about undefined or multiply defined symbols or references. Where are these coming from, and how do I correct them?

Answer: In our system the linker is named "ld". We rarely if ever make a call directly to ld. Rather, ld is called by proxy whenever we call g++ without the "-c" option. It is ld that translates object code to an executable.

What happens is, g++ is a translator from source code to object code. (This is really the compile step.) Then g++ hands off all of its object code (.o files) to ld for the creation of an executable. This is really not part of compiling, technically, but we often think of it as the tail end of compiling a progrem.

Two Simple Rules

Compared to what g++ has to deal with, ld has a simple job. And, ld has some simple rules to live by. The most often encountered are:

Every symbol created in the code must have one and only one definition. Here "symbols" are any identifier in your code, including functions, classes, methods, operators, and plain variables. A "definition" means an explicit recipe for execution. For functions/methods/operators, this means in essence that the implementation code has to have been provided, exactly one time.

One of the symbols must be "main". Yes, "main" is a symbol that is a required part of every C or C++ executable program. Moreover, by rule 1, it must be defined exactly one time. It may not be defined twice, even if the two definitions are identical (ld is NOT smart enough to determine this...)

Error Messages

The error messages you see from ld usually are caused by violations of these rules. The "explanation" is screen output in the form of a primitive table that shows the symbol, where it is first found in the object code, and other info. The table may be for "undefined" symbols (meaning you didn't give a definition for those symbols) or "multiply defined" symbols, meaning that you gave the definition more than once.

These errors are easily correctible. For undefined symbols, you need to add object code implementing those symbols to the files you are giving off to ld. For multiply defined symbols, you have to track down where the unintended second implementation of the symbol is - typically, you find that you have #included the implementation code into another file, while at the same time compiled it separately.

Here are two different versions of these messages for a specific example, caused by omitting xstring.o from the input to the linker. The first is from the linker on Sun/Solaris ("program"):

g++ -W -Wall -o pwtest.x pwtest.o pwserver.o hash.o
Undefined                       first referenced
 symbol                             in file
fsu::operator<<(std::basic_ostream >&, fsu::String const&) pwserver.o
fsu::String::operator[](unsigned int) consthash.o
fsu::operator==(fsu::String const&, fsu::String const&)pwserver.o
fsu::String::~String()              pwserver.o
fsu::String::String()               pwserver.o
fsu::String::operator=(fsu::String const&)pwserver.o
fsu::String::String(fsu::String const&)pwserver.o
fsu::String::Element(unsigned int)  consthash.o
fsu::operator<(fsu::String const&, fsu::String const&)pwserver.o
fsu::String::Cstr() const           pwserver.o
fsu::operator>>(std::basic_istream >&,
fsu::String&)                       pwserver.o
fsu::operator!=(fsu::String const&, fsu::String const&)pwserver.o
fsu::operator+(fsu::String const&, fsu::String const&)pwserver.o

The second is from the same mistake, with messages generated by Intel/Linux ("linprog"):

g++ -W -Wall -o pwtest.x pwtest.o pwserver.o hash.o
pwserver.o(.text+0x109): In function `uidsgn::uidsgn()':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x129): In function `uidsgn::uidsgn()':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x14c): In function `uidsgn::uidsgn(fsu::String const&,
unsigned int)':
: undefined reference to `fsu::String::String(fsu::String const&)'
pwserver.o(.text+0x16e): In function `uidsgn::uidsgn(fsu::String const&,
unsigned int)':
: undefined reference to `fsu::String::String(fsu::String const&)'
pwserver.o(.text+0x190): In function `uidsgn::setuid(fsu::String const&)':
: undefined reference to `fsu::String::operator=(fsu::String const&)'
pwserver.o(.text+0x1ba): In function `uidsgn::uid() const':
: undefined reference to `fsu::String::String(fsu::String const&)'
pwserver.o(.text+0x20a): In function `operator<<(std::basic_ostream >&, uidsgn)':
: undefined reference to `fsu::operator<<(std::basic_ostream >&, fsu::String const&)'
pwserver.o(.text+0x233): In function `operator<<(std::basic_ostream >&, uidsgn)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x250): In function `operator<<(std::basic_ostream >&, uidsgn)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x296): In function `operator<(uidsgn, uidsgn)':
: undefined reference to `fsu::operator<(fsu::String const&, fsu::String
const&)'
pwserver.o(.text+0x2a8): In function `operator<(uidsgn, uidsgn)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x2b7): In function `operator<(uidsgn, uidsgn)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x2d4): In function `operator<(uidsgn, uidsgn)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x2ee): In function `operator<(uidsgn, uidsgn)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x340): In function `uidsgnLessThan::operator()(uidsgn const&,
uidsgn const&) const':
: undefined reference to `fsu::operator<(fsu::String const&, fsu::String
const&)'
pwserver.o(.text+0x352): In function `uidsgnLessThan::operator()(uidsgn const&,
uidsgn const&) const':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x361): In function `uidsgnLessThan::operator()(uidsgn const&,
uidsgn const&) const':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x37e): In function `uidsgnLessThan::operator()(uidsgn const&,
uidsgn const&) const':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x398): In function `uidsgnLessThan::operator()(uidsgn const&,
uidsgn const&) const':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x3ed): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x3ff): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x414): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::Wrap(char const*)'
pwserver.o(.text+0x429): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::Wrap(char const*)'
pwserver.o(.text+0x452): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::Cstr() const'
pwserver.o(.text+0x4aa): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::operator<<(std::basic_ostream >&, fsu::String const&)'
pwserver.o(.text+0x526): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x565): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::operator>>(std::basic_istream >&, fsu::String&)'
pwserver.o(.text+0x5ff): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x619): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x673): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x699): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x717): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x729): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x73e): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::Wrap(char const*)'
pwserver.o(.text+0x753): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::Wrap(char const*)'
pwserver.o(.text+0x77c): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::Cstr() const'
pwserver.o(.text+0x7d4): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::operator<<(std::basic_ostream >&, fsu::String const&)'
pwserver.o(.text+0x850): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::String()'
pwserver.o(.text+0x88f): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::operator>>(std::basic_istream >&, fsu::String&)'
pwserver.o(.text+0x929): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x943): In function `PWServer::PWServer(char const*, char
const*, unsigned int)':
: undefined reference to `fsu::String::~ In function `PWServer::ChangePW(char
const*, char*, char*)':
: undefined reference to `fsu::String::String(char const*)'
pwserver.o(.text+0xd72): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::String::String(char const*)'
pwserver.o(.text+0xe33): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::operator==(fsu::String const&, fsu::String
const&)'
pwserver.o(.text+0xe4d): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0xe64): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0xf02): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0xf11): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0xf20): In function `PWServer::ChangePW(char const*, char*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0xf3b): more undefined references to `fsu::String::~String()'
follow
pwserver.o(.text+0x100f): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::String(char const*)'
pwserver.o(.text+0x1021): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::String(char const*)'
pwserver.o(.text+0x1120): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::operator!=(fsu::String const&, fsu::String
const&)'
pwserver.o(.text+0x113a): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1151): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1243): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1252): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x126f): In function `PWServer::CreateUser(char const*,
char*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1289): more undefined references to `fsu::String::~String()'
follow
pwserver.o(.text+0x12bf): In function `PWServer::DeleteUser(char const*)':
: undefined reference to `fsu::String::String(char const*)'
pwserver.o(.text+0x1320): In function `PWServer::DeleteUser(char const*)':
: undefined reference to `fsu::operator==(fsu::String const&, fsu::String
const&)'
pwserver.o(.text+0x133a): In function `PWServer::DeleteUser(char const*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1351): In function `PWServer::DeleteUser(char const*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1402): In function `PWServer::DeleteUser(char const*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x141c): In function `PWServer::DeleteUser(char const*)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x144f): In function `PWServer::Hash(fsu::String const&,
fsu::String const&)':
: undefined reference to `fsu::operator+(fsu::String const&, fsu::String
const&)'
pwserver.o(.text+0x146f): In function `PWServer::Hash(fsu::String const&,
fsu::String const&)':
: undefined reference to `fsu::String::~String()'
pwserver.o(.text+0x1489): In function `PWServer::Hash(fsu::String const&,fsu::Stu::operator<<(std::basic_ostream >&,fsu::String const&)'
pwserver.o(.text+0x1843): In function `PWServer::Dump(std::basic_ostream >

The Solaris version is in table format and is a little more compact. The Linux version gives more information, in a narrative form. In either case, it is important to READ the error message in order to fix the problem.

Name Mangling

The compiler has to have a way to translate polymorphically used identifiers into unique identifiers at the object code level. For example, member function "classMethod()" of class "className" invoked by an object named "classInstance" might appear as "classInstanceclassNamexyzclassMethodabc23" in the linker symbol table. Usually there is enough info in the mangled name for you to deduce where it came from in the source code.
(Back to FAQs)


Question: Best Practices: Scope of Declared Constants. I take it that declared global constants are acceptable provided that they are useful across multiple scopes. For example, when defining an upper bound on an array that will be passed among several functions or used across different scopes. Would it be safe to say that constants should be defined over the smallest scope possible?

Answer: Where to define constants is a judgement call based on how often they will need to be accessed (to read or change) and by whom. Usually, the closer to the top of the file, and the less "entangled" in the code, the better. My personal preferences are to (1) make them namespace-level or (2) limit their visibility to the containing file. Here's how each of these is done.

  1. Namespace level constants (C++)

    namespace whatEver
    {
      const size_t maximumArraySize = 100;
    
      // more stuff
    
      ...
    } // end namespace whatEver
    

    Then the constant can be access using scope resolution as in

    int A [whatEver::maximumArraySize];
    

  2. File scope (C and C++)

    static const size_t maximumArraySize = 100;
    

    Then the constant can be used by any code inside the same file, but not by code defined elsewhere. This is the handy way C controls namespace polution.

(Back to FAQs)


Question: Best Practices: Scope of Variables. What is the convention (for declaring variables) in C++? Is it moving toward limited scope declarations or is it keeping to the function level scope of C?

Answer: The answer is not really language specific. As a general rule, it is good to limit the scope of variables; however it is also good to write readable code. These goals are not necessarily served by the same hard rules.

C++ and Perl allow the declaration of variables just about anywhere in the block, whereas other languages require declarations to be made at the beginning of the block. Thus C++ and Perl give you more flexibility as a code engineer.

Often I find that readability and correctness are served by dividing the variables into two categories: "meaningful" and "meaningless" to the computation. By this I mean meaningful or meaningless to an outside observer who knows what computation is being done, but not necessarily the details of how it is carried out. This is a judgement call, of course. An example of "meaningful" would be "sum" and "size" in calculating the mean of an array of integers. An example of "meaningless" would be the index variable in a loop that accumulates the sum. Then:

  1. Organize the computation around carefully chosen "meaningful" variable names that serve as self-documentation for the computation, and then declare these "meaningful" variables at the beginning of the block.
  2. Declare the remaining variables with as restricted scope as possible. In particular, it is good practice to limit the scope of a loop counter to the loop itself, as in:

    for (size_t i = 0; i < size; ++i)
    {
      sum += A[i];
    }
    

    Note that the scope of i in the above is inside the loop only. Any attempt to use i below the closing brace would result in a compile error.

This allows the reader of the code to get an idea of how the computation is organized from the start, and it keeps this understanding as simple as possible by not cluttering these declarations with a bunch of incidentals such as "i", "tempVal", "loopCounter", and so on. The convention to keep loop counter scope limited to the loop itself is a highly recommended safety feature. Many errors have been introduced in the maintenance phase of code that used loop variables semantically after the loop ends.

Since Matt brought it up, here's my take on global variables: NEVER in C++.

Firstly, a class variable is "global" to the class, and this usually takes care of any need/desire for globality.

Under the rare circumstances that it is justified to have a variable above class-level scope, then it can be limited by either namespace scope or file scope, as discussed above for constants.

There are some extremely rare cases of true globals floating around C code, such as the Unix "time" structs. These are carefully chosen by the OS designers and documented. They are declared as "extern" variables.

(Back to FAQs)


Question: Return by Reference - 1. In certain situations, such as assignment operators, bracket operators, and I/O operators, the return type is a reference. What does this mean, and how do we handle it in the implementation?

Answer: This is a subtle, and not altogether consistent, area in C++. It has to do with the three possible return types for a typename T:

T Func(...)
T& Func(...)
T* Func(...)

The problem is that the first two use exactly the same syntax inside the implementation of Func:

{
 ...
 return t;
}

where "t" is something of type T. The third "more primitive" return type is inherited from C and must explicitly return a pointer.

The best way to understand this (for me, at least) is to think of the first as "return by value" and the second as "return by reference". This way of thinking emphasizes that we return what looks to be the same kind of object in both cases, just that how it is returned is determined by the return type.
(Back to FAQs)


Question: Return by Reference - 2. OK, I tried to return something by reference and got a compile error. When I changed to return by value, it worked fine. What gives? Any special rules at work here?

Answer: Did you think it would be easy??? The main point of subtlety here is logic: A reference that is returned by a function or operator must have a legal (in scope) object to refer to. If you make a local variable in a function and attempt to return it by reference, you are asking the calling process to take ownership of an object that goes out of scope as soon as the function returns - in other words, as soon as the calling process picks up the execution, the object referred to will no longer exist.

Thus to return an object by reference requires that the object have scope outside the local scope of the function. The usual way this happens is that the reference returned is to an object that was passed in to the function by reference to begin with, as in:

std::istream& operator >> (std::ostream& is, T& t)
{
  // extract a token from is
  // build a type T object from this token
  // place this object in the argument t (passed in by reference)
  return is;
}

Note the stream object is is passed in by reference (NOT const reference), modified during the call, and then returned by reference.
(Back to FAQs)


Question: The explicit keyword: What is the purpose of using explicit in front of a constructor?

Answer: The keyword explicit is used to modify constructors.

The problem: compilers always try to make type conversions instead of returning errors. A 1-parameter constructor is fair game for such implicit conversion. But often the client programmer would prefer to see an error, where it is not likely the programmers intent to convert and integer, say, to a vector. For example:

void f (std::vector <std::string> v);
...
int main()
{
  int x;
  ...
  f(x); // calls f incorrectly, using an int instead of a vector
   ...
}

Note that the incorrect call would be allowed by the compiler if there is a 1-parameter constructor for vector that is not "explicit". This could be a source of strange behavior if the implicit type conversion was not intended.

The "explicit" modifier allows the use of the constructor only when it is actually called explicitly, not as an implicit type conversion mechanism.
(Back to FAQs)


Question: What is the difference between #include"file" and #include<file>, and why is the latter one preferred?

Answer: The first notation is very explicit and inflexible, whereas the second is general and flexible.

#include"file" is used to indicate that the file is located in the same directory as the file that is including it.

#include<file> is used to indicate that the file is somewhere in the search path - either those paths already installed into the compiler (in the case of library headers) or paths supplied by the user in the compile statement, as "-I" flags.

The reason that is is not advised to use "" is that if the two files ever get into different directories, compile will not work without editing the code files (changing "" to <>). If you use <> then all you have to do is add paths to your project, either by notifying your IDE or adding the path to your makefile.

Bottom line: using "" is equivalent to using <> and adding the search path "-I." in the compile statement. But there is no way to recover if you use "" and the files get separated, which is a very common occurrance in a large project.
(Back to FAQs)


Question: What is the best practice for #include notation, and why?

Answer: Using quote delimiters in #include statements hard-codes file location information in your source code files. Consequently, to change file locations you then have to edit the source code files with a new location for the included files. In general, hard coding specific info like this in the source code is not best practice. It spreads out information that should be collected in a single place.

The place where file locations should be recorded is in the project manager. To make this work you always use the angle bracket delimiters for #include statements. The effect is to uncouple include file location from the source code file and move it up into the project manager.

In an IDE, access to the manager is via some feature like "add path" (.net) or "add to project" (eclipse). If you could see under the hood of an IDE, you would find a makefile.

The manager we are using is explicit and decoupled from the text editor: the make utility. The project makefile is the place where we record how the project is organized, where to search for include files, what the dependencies are, etc. (If you haven't looked at the make tutorial, please do so now: read about dependency graphs.)

In general, a meta-principle in software engineering best practice is: don't hard code specific instances of changeable information in scattered locations, rather make these available for (re-)organization in one place. This meta-principle instantiates to various best practices. For example, for constants, it will state that they should be declared at or near the top of a file in one location, or collected into a separate #include file if the constants are used across more than one file. The best practice described here is the instantion of the meta-principle for project management.
(Back to FAQs)


Question: How are virtual method calls implemented?

Answer: See the Wikipedia for a very good treatment.
(Back to FAQs)


Question: Is there a Unix/Linux spell checker?

Answer: Yes, probably many. One that works well and is on our system is invoked with this command (to check spelling in a text file named "myFile"):

aspell -c myFile

This is a good one to have as an alias. (Provided by Daniel Zigrino.)
(Back to FAQs)


Question: How can I create simple command abbreviations?

Answer: Abbreviations can be placed in the system file name ".alias" in your home directory. This file should exist as part of the account setup provided by the system group and already be in your execute paths. (Enter the command "ea" to see if this is working in your account.) Here is a typical contents for .alias

# .alias
alias  a   alias
a      u   unalias
a      ea  'emacs -nw ~/.alias;source ~/.alias;echo "Aliases updated."'
a sp      'aspell -c' 
a e       'emacs -nw'
a efaq    'emacs -nw ~/public_html/courses/FAQ/faq.html'
a la      'ls -al'
a ll      'ls -l'
a lr      'ls -R'
a lls     'll \!* | sort -n +3'
a llsr    'll \!* | sort -n +3 -r'
a llt     'll -t'
a dir     'ls -l'
a f       'finger \!* | less'
a h       history
a j       jobs
a md      mkdir
a qv      quota -v

A couple of things are noteworthy. First, note that "alias" is a command creator. Any command created using alias persists only for that login session. So, you can make a command that goes away after you logout using alias. (There is also the "unalias" command that can be used to wipe one out for the session.) Second, note that the file ".alias" is sourced every time you log in, so aliases in this file are automatically created at login. In this way, they are persistent.

Also note that the command "alias" itself is aliased to "a" and that "ea" is aliased to a sequence of three command: first emacs is called on the .alias file. Second (after emacs returns) this file is sourced. Third, a message is sent to screen telling you that your aliases have been updated. (Use the semi-colon to separate Unix commands when an alias has more than one.) Very neat. So if I wanted to add an alias to check spelling, for example, I would just type "ea", then edit in the new command, then close out emacs. This can be done from any directory.

Custom commands can be quite useful. Note that "efaq" defined above allows a simple 4-letter sequence to begin editing the file of FAQs from any location in file system.
(Back to FAQs)


Question: How can I invoke commands like "elm" on shell from linprog?

Answer: (Courtesy of Stephen Brown) You can't invoke "elm" on the programming machines (linprog, program). A potential way around this is to make use of aliases and ssh. For instance, in my aliases file I have the following:

a shelm ssh -tq shell 'elm'

For all practical purposes this lets me view my email from linprog by typing the command "shelm".

To set up shell so that you can ssh to it from linprog without having to enter your password you can do the following:

  1. Login to shell and create the .ssh directory in your home directory (it probably exists, but create it if it doesn't)
  2. Login to shell and cd to .ssh, then run "ssh-keygen -t rsa"
  3. Hit enter at the passphrase prompts. Hit enter at the filename prompt. A default file id_rsa will be created.
  4. From your home directory on shell run the command " cat .ssh/id_rsa.pub | ssh USERNAME@linprog.cs.fsu.edu 'cat >> .ssh/authorized_keys' ", where you put your username in place of USERNAME.

If everything worked you can now ssh to shell from linprog without being prompted for a password every time. Then to run a command on shell from linprog you just do:

ssh -tq shell 'command-goes-here'

Good luck!
(Back to FAQs)