荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: jjksam ([==面壁大师==]), 信区: Program
标  题: C++ FAQ (part 14 of 14)
发信站: 荔园晨风BBS站 (Mon Jul  1 14:36:25 2002), 转信


From: cline@parashift.com
Sender: cline@parashift.com
Newsgroups: comp.lang.c++,comp.answers,news.answers,alt.comp.lang.learn.c-c++
Subject: C++ FAQ (part 14 of 14)
Summary: Please read this before posting to comp.lang.c++
Followup-To: comp.lang.c++
Reply-To: cline@parashift.com (Marshall Cline)
Distribution: world
Approved: news-answers-request@mit.edu
Expires: +1 month

Archive-name: C++-faq/part14
Posting-Frequency: monthly
Last-modified: Jun 17, 2002
URL: http://www.parashift.com/c++-faq-lite/

AUTHOR: Marshall Cline / cline@parashift.com / 972-931-9470

COPYRIGHT: This posting is part of "C++ FAQ Lite."  The entire "C++ FAQ Lite"
document is Copyright(C)1991-2002 Marshall Cline, Ph.D., cline@parashift.com.
All rights reserved.  Copying is permitted only under designated situations.
For details, see section [1].

NO WARRANTY: THIS WORK IS PROVIDED ON AN "AS IS" BASIS.  THE AUTHOR PROVIDES
NO
WARRANTY WHATSOEVER, EITHER EXPRESS OR IMPLIED, REGARDING THE WORK, INCLUDING
WARRANTIES WITH RESPECT TO ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
PURPOSE.

C++-FAQ-Lite != C++-FAQ-Book: This document, C++ FAQ Lite, is not the same as
the C++ FAQ Book.  The book (C++ FAQs, Cline and Lomow, Addison-Wesley) is
500%
larger than this document, and is available in bookstores.  For details, see
section [3].

==============================================================================

SECTION [35]: Compiler dependencies


[35.1] Where can I download a free C++ compiler?

Check out www.digitalmars.com.

Also check out www.idiom.com/free-compilers/LANG/C++-1.html.

==============================================================================

[35.2] Where can I get more information on using MFC and Visual C++?

The MFC/Visual C++ FAQ (mfcfaq.stingray.com/) is maintained by Michael Pickens
(formerly maintained by Scot Wingo).  Another FAQ is available at
www.mvps.org/vcfaq.

==============================================================================

[35.3] How do I display text in the status bar using MFC?

Use the following code snipped:

 CString s = "Text";
 CStatusBar* p =

(CStatusBar*)AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
 p->SetPaneText(1, s);

This works with MFC v.1.00 which hopefully means it will work with other
versions as well.

==============================================================================

[35.4] How can I decompile an executable program back into C++ source code?

You gotta be kidding, right?

Here are a few of the many reasons this is not even remotely feasible:
 * What makes you think the program was written in C++ to begin with?
 * Even if you are sure it was originally written (at least partially) in C++,
   which one of the gazillion C++ compilers produced it?
 * Even if you know the compiler, which particular version of the compiler was
   used?
 * Even if you know the compiler's manufacturer and version number, what
   compile-time options were used?
 * Even if you know the compiler's manufacturer and version number and
   compile-time options, what third party libraries were linked-in, and what
   was their version?
 * Even if you know all that stuff, most executables have had their debugging
   information stripped out, so the resulting decompiled code will be totally
   unreadable.
 * Even if you know everything about the compiler, manufacturer, version
   number, compile-time options, third party libraries, and debugging
   information, the cost of writing a decompiler that works with even one
   particular compiler and has even a modest success rate at generating code
   would be significant -- on the par with writing the compiler itself from
   scratch.

But the biggest question is not how you can decompile someone's code, but why
do you want to do this? If you're trying to reverse-engineer someone else's
code, shame on you; go find honest work.  If you're trying to recover from
losing your own source, the best suggestion I have is to make better backups
next time.

(Don't bother writing me email saying there are legitimate reasons for
decompiling; I didn't say there weren't.)

==============================================================================

[35.5] Where can I get information about the C++ compiler from {Borland, IBM,
       Microsoft, Sun, etc.}? [UPDATED!]

[Recently updated the link to KAI C++ (in 6/02).]

In alphabetical order by vendor name:
 * Borland C++ 5.0 FAQs: www.reisdorph.com/bcpp/
 * Comeau C++: www.comeaucomputing.com/
 * Digital Mars (free) C++: www.digitalmars.com/
 * DJ C++ ("DJGPP"): www.delorie.com/
 * Edison Design Group C++: www.edg.com/cpp.html
 * GNU C++ ("g++" or "GCC"): gcc.gnu.org/.  Note: a version precompiled for
   Win32 (Cygwin) is available at gccbin.tripod.com/.
 * HP C++: www.hp.com/lang/cpp/
 * IBM VisualAge C++: www.ibm.com/software/ad/vacpp/
 * Intel Reference C++: developer.intel.com/software/products/compilers/
 * KAI C++: developer.intel.com/software/products/kcc/
 * Metrowerks C++: metrowerks.com or www.metrowerks.com
 * Microsoft Visual C++: www.microsoft.com/visualc/
 * Open Watcom C++ (an open-source follow-up to Watcom C++):
   www.openwatcom.org/
 * Portland Group C++: www.pgroup.com
 * Rational APEX C/C++: www.rational.com/products/apex/prodinfo/cpp.jtmpl
 * Silicon Graphics C++: www.sgi.com/developers/devtools/languages/c++.html
 * Sun Visual WorkShop[TM] for C++: www.sun.com/workshop/visual
 * Watcom C++: www.sybase.com/products/archivedproducts/watcomc

[If anyone has other suggestions that should go into this list, please let me
know; thanks; (cline@parashift.com)].

==============================================================================

[35.6] What's the difference between C++ and Visual C++? [NEW!]

[Recently created based on a question from Lavanya Mahashankar (in 6/02).]

C++ is the language itself, Visual C++[35.5] is a compiler that tries to
implement the language.

==============================================================================

[35.7] How do compilers use "over-allocation" to remember the number of
       elements in an allocated array?

Recall that when you delete[] an array, the runtime system magically knows how
many destructors to run[16.13].  This FAQ describes a technique used by some
C++ compilers to do this (the other common technique is to use an associative
array[35.8]).

If the compiler uses the "over-allocation" technique, the code for
p = new Fred[n] looks something like the following.  Note that WORDSIZE is an
imaginary machine-dependent constant that is at least sizeof(size_t), possibly
rounded up for any alignment constraints.  On many machines, this constant
will
have a value of 4 or 8.  It is not a real C++ identifier that will be defined
for your compiler.

 // Original code: Fred* p = new Fred[n];
 char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
 Fred* p = (Fred*) (tmp + WORDSIZE);
 *(size_t*)tmp = n;
 size_t i;
 try {
   for (i = 0; i < n; ++i)
     new(p + i) Fred();           // Placement new[11.10]
 } catch (...) {
   while (i-- != 0)
     (p + i)->~Fred();            // Explicit call to the destructor[11.10]
   operator delete[] ((char*)p - WORDSIZE);
   throw;
 }

Then the delete[] p statement becomes:

 // Original code: delete[] p;
 size_t n = * (size_t*) ((char*)p - WORDSIZE);
 while (n-- != 0)
   (p + n)->~Fred();
 operator delete[] ((char*)p - WORDSIZE);

Note that the address passed to operator delete[] is not the same as p.

Compared to the associative array technique[35.8], this technique is faster,
but more sensitive to the problem of programmers saying delete p rather than
delete[] p.  For example, if you make a programming error by saying delete p
where you should have said delete[] p, the address that is passed to
operator delete(void*) is not the address of any valid heap allocation.  This
will probably corrupt the heap.  Bang! You're dead!

==============================================================================

[35.8] How do compilers use an "associative array" to remember the number of
       elements in an allocated array?

Recall that when you delete[] an array, the runtime system magically knows how
many destructors to run[16.13].  This FAQ describes a technique used by some
C++ compilers to do this (the other common technique is to
over-allocate[35.7]).

If the compiler uses the associative array technique, the code for
p = new Fred[n] looks something like this (where arrayLengthAssociation is the
imaginary name of a hidden, global associative array that maps from void* to
"size_t"):

 // Original code: Fred* p = new Fred[n];
 Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
 size_t i;
 try {
   for (i = 0; i < n; ++i)
     new(p + i) Fred();           // Placement new[11.10]
 } catch (...) {
   while (i-- != 0)
     (p + i)->~Fred();            // Explicit call to the destructor[11.10]
   operator delete[] (p);
   throw;
 }
 arrayLengthAssociation.insert(p, n);

Then the delete[] p statement becomes:

 // Original code: delete[] p;
 size_t n = arrayLengthAssociation.lookup(p);
 while (n-- != 0)
   (p + n)->~Fred();
 operator delete[] (p);

Cfront uses this technique (it uses an AVL tree to implement the associative
array).

Compared to the over-allocation technique[35.7], the associative array
technique is slower, but less sensitive to the problem of programmers saying
delete p rather than delete[] p.  For example, if you make a programming error
by saying delete p where you should have said delete[] p, only the first Fred
in the array gets destructed, but the heap may survive (unless you've replaced
operator delete[] with something that doesn't simply call operator delete, or
unless the destructors for the other Fred objects were necessary).

==============================================================================

[35.9] If name mangling was standardized, could I link code compiled with
       compilers from different compiler vendors?

Short answer: Probably not.

In other words, some people would like to see name mangling standards
incorporated into the proposed C++ ANSI standards in an attempt to avoiding
having to purchase different versions of class libraries for different
compiler
vendors.  However name mangling differences are one of the smallest
differences
between implementations, even on the same platform.

Here is a partial list of other differences:
 * Number and type of hidden arguments to member functions.
   - is this handled specially?
   - where is the return-by-value pointer passed?
 * Assuming a v-table[20.3] is used:
   - what is its contents and layout?
   - where/how is the adjustment to this made for multiple and/or virtual
     inheritance?
 * How are classes laid out, including:
   - location of base classes?
   - handling of virtual base classes?
   - location of v-pointers[20.3], if they are used at all?
 * Calling convention for functions, including:
   - where are the actual parameters placed?
   - in what order are the actual parameters passed?
   - how are registers saved?
   - where does the return value go?
   - does caller or callee pop the stack after the call?
   - special rules for passing or returning structs or doubles?
   - special rules for saving registers when calling leaf functions?
 * How is the run-time-type-identification laid out?
 * How does the runtime exception handling system know which local objects
need
   to be destructed during an exception throw?

==============================================================================

[35.10] GNU C++ (g++) produces big executables for tiny programs; Why?

libg++ (the library used by g++) was probably compiled with debug info (-g).
On some machines, recompiling libg++ without debugging can save lots of disk
space (approximately 1 MB; the down-side: you'll be unable to trace into
libg++
calls).  Merely strip-ping the executable doesn't reclaim as much as
recompiling without -g followed by subsequent strip-ping the resultant a.out's.


Use size a.out to see how big the program code and data segments really are,
rather than ls -s a.out which includes the symbol table.

==============================================================================

[35.11] Is there a yacc-able C++ grammar?

The primary yacc grammar you'll want is from Ed Willink.  Ed believes his
grammar is fully compliant with the ISO/ANSI C++ standard[6.12], however he
doesn't warrant it: "the grammar has not," he says, "been used in anger." You
can get the grammar without action routines
<http://www.computing.surrey.ac.uk/research/dsrg/fog/CxxGrammar.y> or the
grammar with dummy action routines
<http://www.computing.surrey.ac.uk/research/dsrg/fog/CxxTester.y>.  You can
also get the corresponding lexer
<http://www.computing.surrey.ac.uk/research/dsrg/fog/CxxLexer.l>.  For those
who are interested in how he achieves a context-free parser (by pushing all
the
ambiguities plus a small number of repairs to be done later after parsing is
complete), you might want to read chapter 4 of his thesis
<http://www.computing.surrey.ac.uk/research/dsrg/fog/FogThesis.pdf>.

There is also a very old yacc grammar that doesn't support templates,
exceptions, nor namespaces; plus it deviates from the core language in some
subtle ways.  You can get that grammar here
<http://www.empathy.com/pccts/roskind.zip> or here
<http://srawgw.sra.co.jp/.a/pub/cmd/c++grammar2.0.tar.gz>.

==============================================================================

[35.12] What is C++ 1.2? 2.0? 2.1? 3.0?

These are not versions of the language, but rather versions of Cfront, which
was the original C++ translator implemented by AT&T.  It has become generally
accepted to use these version numbers as if they were versions of the language
itself.

Very roughly speaking, these are the major features:
 * 2.0 includes multiple/virtual inheritance and pure virtual[22.4] functions
 * 2.1 includes semi-nested classes and delete[] pointerToArray
 * 3.0 includes fully-nested classes, templates and i++ vs. ++i
 * 4.0 will include exceptions

==============================================================================

[35.13] Is it possible to convert C++ to C? [UPDATED!]

[Recently added a URL for Cfront <http://www.unipress.com/toolkit/> and
reworded the third bullet (in 5/02).]

Depends on what you mean.  If you mean, Is it possible to convert C++ to
readable and maintainable C-code? then sorry, the answer is No -- C++ features
don't directly map to C, plus the generated C code is not intended for humans
to follow.  If instead you mean, Are there compilers which convert C++ to C
for
the purpose of compiling onto a platform that yet doesn't have a C++ compiler?
then you're in luck -- keep reading.

A compiler which compiles C++ to C does full syntax and semantic checking on
the program, and just happens to use C code as a way of generating object code.

Such a compiler is not merely some kind of fancy macro processor.  (And please
don't email me claiming these are preprocessors -- they are not -- they are
full compilers.) It is possible to implement all of the features of ISO
Standard C++ by translation to C, and except for exception handling, it
typically results in object code with efficiency comparable to that of the
code
generated by a conventional C++ compiler.

Here are some products that perform compilation to C (note: if you know of any
other products that do this, please email me):
 * Comeau Computing <http://www.comeaucomputing.com> offers a compiler based
on
   Edison Design Group's front end <http://www.edg.com> that outputs C code.
 * Cfront <http://www.unipress.com/toolkit/>, the original implementation of
   C++, done by Bjarne Stroustrup and others at AT&T, generates C code.
   However it has two problems: it's been difficult to obtain a license since
   the mid 90s when it started going through a maze of ownership changes, and
   development ceased at that same time and so it is doesn't get bug fixes and
   doesn't support any of the newer language features (e.g., exceptions,
   namespaces, RTTI, member templates).
 * Contrary to popular myth, as of this writing there is no version of g++
that
   translates C++ to C.  Such a thing seems to be doable, but I am not aware
   that anyone has actually done it (yet).

Note that you typically need to specify the target platform's CPU, OS and C
compiler so that the generated C code will be specifically targeted for this
platform.  This means: (a) you probably can't take the C code generated for
platform X and compile it on platform Y; and (b) it'll be difficult to do the
translation yourself -- it'll probably be a lot cheaper/safer with one of
these
tools.

One more time: do not email me saying these are just preprocessors -- they are
not -- they are compilers.

==============================================================================

SECTION [36]: Miscellaneous technical issues


[36.1] How can I generate HTML documentation for my classes? Does C++ have
       anything similar to javadoc?

Yes.  Here are a few (listed alphabetically by tool name):
 * ccdoc <http://www.joelinoff.com/ccdoc/> supports javadoc-like syntax with
   various extensions.  It's freely copiable and customizable.
 * doc++ <http://docpp.sourceforge.net/> generates HTML or TeX.  Supports
   javadoc-like syntax with various extensions.  Open Source.
 * doxygen <http://www.doxygen.org/> generates HTML, LaTeX or RTF.  Supports
   javadoc-like syntax with various extensions.  Open Source.

Other documentation tools are listed at
webnz.com/robert/cpp_site.html#Documentation.

==============================================================================

[36.2] What should be done with macros that contain if?

First, the best thing to do is get rid of the macro if at all possible.  In
fact, get rid of all macros: they're evil[6.14] in 4 different ways:
evil#1[9.3], evil#2[36.2], evil#3[36.3], and evil#4[36.4], regardless of
whether the contain an if (but they're especially evil if they contain an if).

But if you can't (or don't want to) kill the macro that contains an if, here's
how to make it less evil[6.14]:

Suppose the macro looks like this:

 #define MYMACRO(a,b) \
     if (xyzzy) asdf()

This will cause big problems if someone uses that macro in an if statement:

 if (whatever)
     MYMACRO(foo,bar);
 else
     baz;

The problem is that the else baz nests with the wrong if: the compiler sees
this:

 if (whatever)
     if (xyzzy) asdf();
     else baz;

Obviously that's a bug.

The easy solution is to require {...} everywhere, but there's another solution
that I prefer even if there's a coding standard that requires {...} everywhere
(just in case someone somewhere forgets): add a balancing else to the macro
definition:

 #define MYMACRO(a,b) \
     if (xyzzy) asdf(); \
     else

Now the compiler will see a balanced set of ifs and elses:

 if (whatever)
     if (xyzzy)
         asdf();
     else
         ;  // that's an empty statement
 else
     baz;

Like I said, I personally do the above even when the coding standard calls for
{...} in all the ifs.  Call me paranoid, but I sleep better at night and my
code has fewer bugs.

Note: you need to make sure to put a ; at the end of the macro usage (not at
the end of the macro definition!!).  For example, the macro usage should look
like this:

 if (whatever)
     MYMACRO(foo,bar);  // right: there is a ; after MYMACRO(...)
 else
     baz;

Note: there is another #define macro (do {...} while (false)) that is fairly
popular, but that has some strange side-effects when used in C++[36.3].

==============================================================================

[36.3] What should be done with macros that have multiple lines?

Answer: Choke, gag, cough.  Macros are evil[6.14] in 4 different ways:
evil#1[9.3], evil#2[36.2], evil#3[36.3], and evil#4[36.4].  Kill them all!!

But if you can't (or don't want to) kill them, here's how to make them less
evil[6.14]:

Suppose the macro looks like this:

 #define MYMACRO(a,b) \
     statement1; \
     statement2; \
     ... \
     statementN;

This can cause problems if someone uses the macro in a context that demands a
single statement.  E.g.,

 while (whatever)
     MYMACRO(foo, bar);

The naive solution is to wrap the statements inside {...}, such as this:

 #define MYMACRO(a,b) \
     { \
         statement1; \
         statement2; \
         ... \
         statementN; \
     }

But this will cause compile-time errors with things like the following:

 if (whatever)
     MYMACRO(foo, bar);
 else
     baz;

since the compiler will see a } ; else which is illegal:

 if (whatever)
 {
     statement1;
     statement2;
     ...
     statementN;
 };  // ERROR: { } cannot have a ; before an else
 else
     baz;

The usual solution in C was to wrap the statements inside a do { <statements
go
here> } while (false), since that will execute the <statements go here> part
exactly once.  E.g., the macro might look like this:

 #define MYMACRO(a, b) \
     do { \
         statement1; \
         statement2; \
         ... \
         statementN; \
     } while (false)

Note that there is no ; at the end of the macro definition.  The ; gets added
by the user of the macro, such as the following:

 if (whatever)
     MYMACRO(foo, bar);  // The ; is added here
 else
     baz;

This will expand to the following (note that the ; added by the user goes
after
(and completes) the "} while (false)" part):

 if (whatever)
     do {
         statement1;
         statement2;
         ...
         statementN;
     } while (false);
 else
     baz;

The only problem with this is that it looks like a loop, and some C++
compilers
refuse to "inline expand" any method that has a loop in it.

So in C++ the best solution is to wrap the statements in an if (true) {
<statements go here> } else construct (note that the else is dangling, just
like the situation described in the previous FAQ):

 #define MYMACRO(a, b) \
     if (true) { \
         statement1; \
         statement2; \
         ... \
         statementN; \
     } else

Now the code will expand into this (note the balanced set of ifs and elses):

 if (whatever)
     if (true) {
         statement1;
         statement2;
         ...
         statementN;
     } else
         ;  // that's a null statement
 else
     baz;

==============================================================================

[36.4] What should be done with macros that need to paste two tokens together?

Groan.  I really hate macros.  Yes they're useful sometimes, and yes I use
them.  But I always wash my hands afterwards.  Twice.  Macros are evil[6.14]
in
4 different ways: evil#1[9.3], evil#2[36.2], evil#3[36.3], and evil#4[36.4].

Okay, here we go again, desperately trying to make an inherently evil thing a
little less evil[6.14].

First, the basic approach is use the ISO/ANSI C and ISO/ANSI C++ "token
pasting" feature: ##.  On the surface this would look like the following:

Suppose you have a macro called "MYMACRO", and suppose you're passing a token
as the parameter of that macro, and suppose you want to concatenate that token
with the token "Tmp" to create a variable name.  For example, the use of
MYMACRO(Foo) would create a variable named FooTmp and the use of MYMACRO(Bar)
would create a variable named BarTmp.  In this case the naive approach would
be
to say this:

 #define MYMACRO(a) \
     /*...*/ a ## Tmp /*...*/

However you need a double layer of indirection when you use ##.  Basically you
need to create a special macro for "token pasting" such as:

 #define name2(a,b)         name2_hidden(a,b)
 #define name2_hidden(a,b)  a ## b

Trust me on this -- you really need to do this! (And please nobody write me
saying it sometimes works without the second layer of indirection. Try
concatenating a symbol with __LINE__ and see what happens then.)

Then replace your use of a ## Tmp with name2(a,Tmp):

 #define MYMACRO(a) \
     /*...*/ name2(a,Tmp) /*...*/

And if you have a three-way concatenation to do (e.g., to paste three tokens
together), you'd create a name3() macro like this:

 #define name3(a,b,c)         name3_hidden(a,b,c)
 #define name3_hidden(a,b,c)  a ## b ## c

==============================================================================

[36.5] Why can't the compiler find my header file in #include "c:\test.hpp" ?

Because "\t" is a tab character.

You should use forward slashes ("/") rather than backslashes ("\") in your
#include filenames, even on an operating system that uses backslashes such as
DOS, Windows, OS/2, etc.  For example:

 #if 1
   #include "/version/next/alpha/beta/test.hpp"    // RIGHT!
 #else
   #include "\version\next\alpha\beta\test.hpp"    // WRONG!
 #endif

Note that you should use forward slashes ("/") on all your filenames[15.14],
not just on your #include files.

==============================================================================

[36.6] What are the C++ scoping rules for for loops?

Yep.

The following code used to be legal, but not any more, since i's scope is now
inside the for loop only:

 for (int i = 0; i < 10; ++i) {
   // ...
   if ( /* something weird */ )
     break;
   // ...
 }

 if (i != 10) {
   // We exited the loop early; handle this situation separately
   // ...
 }

If you're working with some old code that uses a for loop variable after the
for loop, the compiler will (hopefully!) give you wa warning or an error
message such as "Variable i is not in scope".

Unfortunately there are cases when old code will compile cleanly, but will do
something different -- the wrong thing.  For example, if the old code has a
global variable i, the above code if (i != 10) silently change in meaning from
the for loop variable i under the old rule to the global variable i under the
current rule.  This is not good.  If you're concerned, you should check with
your compiler to see if it has some option that forces it to use the old rules
with your old code.

Note: You should avoid having the same variable name in nested scopes, such as
a global i and a local i.  In fact, you should avoid globals althogether
whenever you can.  If you abided by these coding standards in your old code,
you won't be hurt by a lot of things, including the scoping rules for for loop
variables.

Note: If your new code might get compiled with an old compiler, you might want
to put {...} around the for loop to force even old compilers to scope the loop
variable to the loop.  And please try to avoid the temptation to use macros
for
this.  Remember: macros are evil[6.14] in 4 different ways: evil#1[9.3],
evil#2[36.2], evil#3[36.3], and evil#4[36.4].

==============================================================================

[36.7] Why can't I overload a function by its return type?

If you declare both char f() and float f(), the compiler gives you an error
message, since calling simply f() would be ambiguous.

==============================================================================

[36.8] What is "persistence"? What is a "persistent object"?

A persistent object can live after the program which created it has stopped.
Persistent objects can even outlive different versions of the creating program,

can outlive the disk system, the operating system, or even the hardware on
which the OS was running when they were created.

The challenge with persistent objects is to effectively store their member
function code out on secondary storage along with their data bits (and the
data
bits and member function code of all member objects, and of all their member
objects and base classes, etc).  This is non-trivial when you have to do it
yourself.  In C++, you have to do it yourself.  C++/OO databases can help hide
the mechanism for all this.

==============================================================================

[36.9] Why is floating point so inaccurate? Why doesn't this print 0.43?

 #include <iostream>

 int main()
 {
   float a = 1000.43;
   float b = 1000.0;
   std::cout << a - b << '\n';
 }

(On one C++ implementation, this prints 0.429993)

Disclaimer: Frustration with rounding/truncation/approximation isn't really a
C++ issue; it's a computer science issue.  However, people keep asking about
it
on comp.lang.c++, so what follows is a nominal answer.

Answer: Floating point is an approximation.  The IEEE standard for 32 bit
float
supports 1 bit of sign, 8 bits of exponent, and 23 bits of mantissa.  Since a
normalized binary-point mantissa always has the form 1.xxxxx... the leading 1
is dropped and you get effectively 24 bits of mantissa.  The number 1000.43
(and many, many others) is not exactly representable in float or double format.

1000.43 is actually represented as the following bitpattern (the "s" shows the
position of the sign bit, the "e"s show the positions of the exponent bits,
and
the "m"s show the positions of the mantissa bits):

     seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
     01000100011110100001101110000101

The shifted mantissa is 1111101000.01101110000101 or 1000 + 7045/16384.  The
fractional part is 0.429992675781.  With 24 bits of mantissa you only get
about
1 part in 16M of precision for float.  The double type provides more precision
(53 bits of mantissa).

==============================================================================

[36.10] How can I create two classes that both know about each other?

Use a forward declaration.

Sometimes you must create two classes that use each other.  This is called a
circular dependency.  For example:

 class Fred {
 public:
   Barney* foo();  // Error: Unknown symbol 'Barney'
 };

 class Barney {
 public:
   Fred* bar();
 };

The Fred class has a member function that returns a Barney*, and the Barney
class has a member function that returns a Fred.  You may inform the compiler
about the existence of a class or structure by using a "forward declaration":

 class Barney;

This line must appear before the declaration of class Fred.  It simply informs
the compiler that the name Barney is a class, and further it is a promise to
the compiler that you will eventually supply a complete definition of that
class.

==============================================================================

[36.11] What special considerations are needed when forward declarations are
        used with member objects?

The order of class declarations is critical.

The compiler will give you a compile-time error if the first class contains an
object (as opposed to a pointer to an object) of the second class.  For
example,

 class Fred;  // Okay: forward declaration[36.10]

 class Barney {
   Fred x;  // Error: The declaration of Fred is incomplete
 };

 class Fred {
   Barney* y;
 };

One way to solve this problem is to reverse order of the classes so the "used"
class is defined before the class that uses it:

 class Barney;  // Okay: forward declaration[36.10]

 class Fred {
   Barney* y;  // Okay: the first can point to an object of the second
 };

 class Barney {
   Fred x;  // Okay: the second can have an object of the first
 };

Note that it is never legal for each class to fully contain an object of the
other class since that would imply infinitely large objects.  In other words,
if an instance of Fred contains a Barney (as opposed to a Barney*), and a
Barney contains a Fred (as opposed to a Fred*), the compiler will give you an
error.

==============================================================================

[36.12] What special considerations are needed when forward declarations are
        used with inline functions?

The order of class declarations is critical.

The compiler will give you a compile-time error if the first class contains an
inline function that invokes a member function of the second class.  For
example,

 class Fred;  // Okay: forward declaration[36.10]

 class Barney {
 public:
   void method()
   {
     x->yabbaDabbaDo();  // Error: Fred used before it was defined
   }
 private:
   Fred* x;  // Okay: the first can point to an object of the second
 };

 class Fred {
 public:
   void yabbaDabbaDo();
 private:
   Barney* y;
 };

One way to solve this problem is to move the offending member function into
the
Barney.cpp file as a non-inline member function.  Another way to solve this
problem is to reverse order of the classes so the "used" class is defined
before the class that uses it:

 class Barney;  // Okay: forward declaration[36.10]

 class Fred {
 public:
   void yabbaDabbaDo();
 private:
   Barney* y;  // Okay: the first can point to an object of the second
 };

 class Barney {
 public:
   void method()
   {
     x->yabbaDabbaDo();  // Okay: Fred is fully defined at this point
   }
 private:
   Fred* x;
 };

Just remember this: Whenever you use forward declaration[36.10], you can use
only that symbol; you may not do anything that requires knowledge of the
forward-declared class.  Specifically you may not access any members of the
second class.

==============================================================================

[36.13] Why can't I put a forward-declared class in a std::vector<>?

Because the std::vector<> template needs to know the sizeof() its contained
elements, plus the std::vector<> probably accesses members of the contained
elements (such as the copy constructor, the destructor, etc.).  For example,

 class Fred;  // Okay: forward declaration[36.10]

 class Barney {
   std::vector<Fred> x;  // Error: the declaration of Fred is incomplete
 };

 class Fred {
   Barney* y;
 };

One solution to this problem is to change Barney so it uses a std::vector<> of
Fred pointers rather than a std::vector<> of Fred objects:

 class Fred;  // Okay: forward declaration[36.10]

 class Barney {
   std::vector<Fred*> x;  // Okay: Barney can use Fred pointers
 };

 class Fred {
   Barney* y;
 };

Another solution to this problem is to reverse the order of the classes so
Fred
is defined before Barney:

 class Barney;  // Okay: forward declaration[36.10]

 class Fred {
   Barney* y;  // Okay: the first can point to an object of the second
 };

 class Barney {
   std::vector<Fred> x;  // Okay: Fred is fully defined at this point
 };

Just remember this: Whenever you use a class as a template parameter, the
declaration of that class must be complete and not simply forward
declared[36.10].

==============================================================================

[36.14] Why doesn't my floating-point comparison work?

Because floating point arithmetic is different from real number arithmetic.

Here's a simple example:

 double x = 1.0 / 10.0;
 double y = x * 10.0;
 if (y != 1.0)
   std::cout << "surprise: " << y << " != 1\n";

The above "surprise" message will appear on some (but not all)
compilers/machines.  But even if your particular compiler/machine doesn't
cause
the above "surprise" message (and if you write me telling me whether it does,
you'll show you've missed the whole point of this FAQ), floating point will
surprise you at some point.  So read this FAQ and you'll know what to do.

The reason floating point will surprise you is that float and double values
are
normally represented using a finite precision binary format.  In other words,
floating point numbers are not real numbers.  For example, in your machine's
floating point format it might be impossible to exactly represent the number
0.1.  By way of analogy, it's impossible to exactly represent the number one
third in decimal format (unless you use an infinite number of digits).

To dig a little deeper, let's examine what the decimal number 0.625 means.
This number has a 6 in the "tenths" place, a 2 in the "hundreths" place, and a
5 in the "thousanths" place.  In other words, we have a digit for each power
of
10.  But in binary, we might, depending on the details of your machine's
floating point format, have a bit for each power of 2.  So the fractional part
might have a "halves" place, a "quarters" place, an "eighths" place,
"sixteenths" place, etc., and each of these places has a bit.

Let's pretend your machine represents the fractional part of floating point
numbers using the above scheme (it's normally more complicated than that, but
if you already know exactly how floating point numbers are stored, chances are
you don't need this FAQ to begin with, so look at this as a good starting
point).  On that pretend machine, the bits of the fractional part of 0.625
would be 101: 1 in the "halves" place, 0 in the "quarters" place, and 1 in the
"eighths" place.  In other words, 0.625 is 1/2 + 1/8.

But on this pretend machine, 0.1 cannot be represented exactly since it cannot
be formed as a sum of (negative) powers of 2 -- at least not without an
infinite number of (negative) powers of 2.  We can get close, but we can't
represent it exactly.  In particular we'd have a 0 in the "halves" place, a 0
in the "quarters" place, a 0 in the "eighths" place, and finally a 1 in the
"sixteenths" place, leaving a remainder of 1/10 - 1/16 = 3/80.  Figuring out
the other bits is left as an exercise (hint: look for a repeating bit-pattern).


The message is that some floating point numbers cannot always be represented
exactly, so comparisons don't always do what you'd like them to do.  In other
words, if the computer actually multiplies 10.0 by 1.0/10.0, it might not
exactly get 1.0 back.

That's the problem.  Now here's the solution: be very careful when comparing
floating point numbers for equality (or when doing other things with floating
point numbers; e.g., finding the average of two floating point numbers seems
simple but to do it right requires an if/else with at least three cases).

Here's the wrong way to do it:

 void dubious(double x, double y)
 {
   // ...

   if (x == y)  // Dubious!
     foo();

   // ...
 }

If what you really want is to make sure they're "very close" to each other
(e.g., if variable a contains the value 1.0 / 10.0 and you want to see
if (10*a == 1)), you'll probably want to do something fancier than the above:

 void smarter(double x, double y)
 {
   // ...

   if (isEqual(x, y))  // Smarter!
     foo();

   // ...
 }

Here's the isEqual() function:

 inline bool isEqual(double x, double y)
 {
   // left as an exercise for the reader :-)
   // see one of the references below
   ...
 }

For the definition for the above function, check out references such as the
following (in random order):
 * Knuth, Donald E., The Art of Computer Programming, Volume II: Seminumerical
   Algorithms, Addison-Wesley, 1969.
 * LAPACK -- Linear Algebra Subroutine Library, www.siam.org
 * Stoer, J. and Bulirsch, R., Introduction to Numerical Analysis, Springer
   Verlag, in German.
 * Isaacson, E. and Keller, H., Analysis of Numerical Methods, Dover.
 * Ralston and Rabinowitz, A First Course in Numerical Analysis: Second
   Edition, Dover.
 * Press et al., Numerical Recipes.
 * Kahan, W., http.cs.berkeley.edu/~wkahan/.

Reminder: be sure to check out all the other primitives, such as averages,
solutions to the quadratic equation, etc., etc.  Do not assume the formulas
you
learned in High School will work with floating point numbers!

==============================================================================

SECTION [37]: Miscellaneous environmental issues


[37.1] Is there a TeX or LaTeX macro that fixes the spacing on "C++"?

Yes.

Here are two LaTeX macros for the word "C++".  They prevent line breaks
between
the C and "++", and the first packs the two "+"s close to each other but the
second does not.  Try them both and see which one you like best.

 \newcommand{\CC}{C\nolinebreak\hspace{-.05em}\raisebox{.4ex}{\tiny\bf
+}\nolinebreak\hspace{-.10em}\raisebox{.4ex}{\tiny\bf +}}

 \def\CC{{C\nolinebreak[4]\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}}

Here are two more LaTeX macros for the word "C++".  They allow line breaks
between the C and "++", which may not be desirable, but they're included here
just in case.

 \def\CC{C\raise.22ex\hbox{{\footnotesize +}}\raise.22ex\hbox{\footnotesize
+}}

 \def\CC{{C\hspace{-.05em}\raisebox{.4ex}{\tiny\bf ++}}}

==============================================================================

[37.2] Are there any pretty-printers that reformat C++ source code?

In alphabetical order:
 * A2PS is a Unix-based pretty-printer.  It is available from
   www.infres.enst.fr/~demaille/a2ps/
 * Artistic Style is a reindenter and reformatter of C++, C and Java source
   code.  It is available from astyle.sourceforge.net/
 * C++2LaTeX is a LaTeX pretty printer.  It is available from
   mirriwinni.cse.rmit.edu.au/ftp/pub/languages/C++2LaTeX-4.0.tar.gz
 * C-Clearly by V Communications, Inc. is a Windows program that comes with
   standard formatting templates and also allows you to customize your own.
   www.mixsoftware.com/product/ccl.htm
 * GNU indent program may help.  It's available at
   www.arceneaux.com/indent.html.  You can also find an "official" GNU mirror
   site by looking at www.gnu.org/order/ftp.html or perhaps the original GNU
   site, ftp://prep.ai.mit.edu/pub/gnu/ (e.g., if the current version is 1.9.1
   you could use ftp://prep.ai.mit.edu/pub/gnu/indent-1.9.1.tar.gz).
 * "HPS Beauty" is reported to be a Windows 95/98/NT4/NT2000 utility that
   beautifies C/C++ source code based on rules.  The interface is entirely GUI,

   but HPS Beauty may also be run from the command line.  It supports style
   files, which allow you to save and restore groups of settings.  HPS Beauty
   also offers an optional visual results window, that shows both the before
   and the after file.  Optional HTML output allows you to view source code
   with syntax highlighting in your browser.  www.highplains.net.
 * "Source Styler for C++" has lots of bells and whistles.  It is a commercial
   product with a free 15-day trial period.  It seems to offer control over
   tons of different features.  www.ochresoftware.com/.
 * tgrind is a Unix based pretty printer.  It usually comes with the public
   distribution of TeX and LaTeX in the directory
   "...tex82/contrib/van/tgrind".  A more up-to-date version of tgrind by
Jerry
   Leichter can be found on: ftp://venus.ycc.yale.edu/pub in [.TGRIND].  [Note:

   If anyone has an updated URL for tgrind, please let me know
   (cline@parashift.com).]

Finally, you might consider lgrind which is another C++ to LaTeX translator
(check for the closest mirror site of the ctan archive
<ftp://ftp.tex.ac.uk/pub/archive/README.mirrors>).  The following is a grind
definition for C++ (but this one doesn't recognize some new keywords such as
bool or wchar_t, and it doesn't recognize a file ending with .cpp as C++):

 C++|c++|CC:\
    :pb=\p\d?\(:cf:np=\)\d?;:bb={:be=}:\
    :cb=/*:ce=*/:ab=//:ae=$:sb=":se=\e":lb=':\
    :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
    :le=\e':tl:id=_~\::\
    :kw=asm auto break case cdecl char continue default do double else\
    enum extern far float for fortran goto huge if int interrupt long\
    near pascal register return short signed sizeof static struct\
    switch typedef union unsigned while void\
    #define #else #endif #if #ifdef #ifndef #include #undef # define\
    endif ifdef ifndef include undef defined #pragma\
    class const delete friend inline new operator overload private\
    protected public template this virtual:

==============================================================================

[37.3] Is there a C++-mode for GNU emacs? If so, where can I get it?

Yes, there is a C++-mode for GNU emacs.

The latest and greatest version of C++-mode (and C-mode) is implemented in the
file cc-mode.el.  It is an extension of Detlef and Clamen's version.  A
version
is included with emacs.  Newer version are available from the elisp archives.

==============================================================================

[37.4] Where can I get OS-specific questions answered (e.g., BC++, DOS,
       Windows, etc)?

See one of the following:
 * MS-DOS issues: comp.os.msdos.programmer
 * MS-Windows issues: comp.windows.ms.programmer
 * Unix issues: comp.unix.programmer
 * Borland C++ issues (e.g., OWL, BC++ compiler bugs, general C++ concepts,
   windows programming):
   - Using your Web browser: www.cs.rpi.edu/~wiseb/owl-list/
   - To get on the mailing list: send an e-mail message with the word
     "SUBSCRIBE" in the Subject: line to majordomo@netlab.cs.rpi.edu
   - To get the FAQ:
     ftp://ftp.netlab.cs.rpi.edu/pub/lists/owl-list-faq/drafts/owl_faq.hlp

==============================================================================

[37.5] Why does my DOS C++ program says "Sorry: floating point code not
       linked"?

The compiler attempts to save space in the executable by not including the
float-to-string format conversion routines unless they are necessary, but
sometimes it guesses wrong, and gives you the above error message.  You can
fix
this by (1) using <iostream> instead of <cstdio>, or (2) by including the
following function somewhere in your compilation (but don't call it!):

 static void dummyfloat(float *x) { float y; dummyfloat(&y); }

See the FAQ on stream I/O[15.1] for more reasons to use <iostream> vs.
<cstdio>.

==============================================================================

[37.6] Why does my BC++ Windows app crash when I'm not running the BC45 IDE?

If you're using BC++ for a Windows app, and it works OK as long as you have
the
BC45 IDE running, but when the BC45 IDE is shut down you get an exception
during the creation of a window, then add the following line of code to the
InitMainWindow() member function of your application
(YourApp::InitMainWindow()):

 EnableBWCC(TRUE);

==============================================================================


--
   mm       ★__      __  __ __★______ ______ __  __★
/^(  )^\      █      █  █/    █____ █__█ █∨█
\,(..),/  ▅__█  ▅__█  █\__  ▂__█ █  █ █  █
  V~~V   ▇▆▅▃▁I'm a bat. I'm very bad!^Q^_▃▄▆▇ 你好!^_^欢迎大家到linux

※ 修改:·jjksam 於 Jul  1 14:44:47 修改本文·[FROM: 192.168.0.146]
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店