荔园在线

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

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


发信人: Version (Who makes history and why), 信区: Program
标  题: [FAQ]C++和C常见问题答疑(转寄)
发信站: 荔园晨风BBS站 (Thu Apr 24 18:23:51 2003), 站内信件


转自http://www.comeaucomputing.com/techtalk/

Tech Talk About C++ and C
Comeau C++ and C FAQ
Copyright © 2000-2002 Comeau Computing. All rights reserved. Note that th
is is a live web page, in the sense that we'll be adding new discussions as ap
propriate (we probably have 5 or so more topics already planned), so stop by f
rom time to time. This web page is also under construction (Version 0.9z7, Apr
il 3, 2003), so if you see something not right, please email us about it.
As well, take a look at our Other FAQs, the Comeau Templates FAQ and the the C
omeau C99 FAQ

The intent of this page is to address questions about C++ and C that come up o
ften, perhaps too often. However, it is exactly the frequency of these topics
that is the reason for including a discussion of them below. These issues usua
lly come up as having originated from a misleading statement commonly made, or
 from code shown in a book. These points have found themselves here as the res
ult of our connection to the C++ and C communities for 20 years, whether teach
ing, helping in newsgroups, providing tech support for Comeau C++, or just pla
in listening to folks' issues. Some of the topics below can be found in other
FAQs, however, here we try to offer more information on the respective topics,
 as well as issues related to them. Here's the current topics:

What book do you recommend?
Where is the FAQ for the various C and C++ newsgroups?
Can I really get the C++ Standard electronically for $18?
Can I get Standard C electronically too?
What's wrong with code that uses void main()?
What about returning from main()?
Where does the int returned from main() go?
What's the difference between endl and '\n'?
Why can't I fflush(stdin), or any input stream??
How do I remove all chars from a stream??
Why can't my compiler find cout, or anything from the Standard library??
Is delete the same as delete []?
What's std or std::?
What happened to the .h suffix on a header file?
Is iostream.h ok?
Why is an unnamed namespace used instead of static?
Why does C++ allow unnamed function parameters?
What are header file "include guards"?
What are header file "code wrappers"?
How can two struct/classes refer to each other?
What's the scope of a for loop declaration?
What does for(;;) mean?
What's the difference between #define and const?
Why is the preprocessor frowned upon?
How do I clear the screen?
How do I change the color of the screen?
How does one erase the current line...And questions like this?
How do I read just one character, w/o a return?
How to convert a char array or C++ string to an int?
How to convert an int to a char array or C++ string?
How to convert a string to a char *?
Why does C++ have a string when there is already char *?
How does C++'s string differ from C's?
Which string do I use if I want a const string?
What's the difference between member initializing and assignment while constru
cting?
How to get the dimension/bounds of an array?
Why can't I overload a function on return types?
Why can't I convert a char ** to a const char **?
How many bits are in a byte?
Is there a BOOL type?
How do I create an array of booleans?
How do I print out a value in binary?
How do I code a binary literal?
How can I execute another program from my program?
What's this "POD" thing in C++ I keep hearing about?
How can C++ functions call C functions?
How can C functions call C++ functions?
What's this extern "C" thing?
Why is there a const after some function names?
void SomeClass::MemberFunc() const { /*WHY THE CONST?*/ }?
What is the mutable keyword?
What's the difference between C++ and VC++?
What's the difference between C++ and Borland C++?
What's an INTERNAL COMPILER ERROR?
What is the template typename keyword used for?
What's the difference between typename and typedef?
What does the ++ in C++ stand for?
How do you pronounce C++?
Do you have a question to add??

------------------------------------------------------------------------------
--

What book do you recommend?
We don't recommend a book. It's naive to expect that one book could be so enco
mpassing as to satisfy everybody and every topic. Therefore, we suggest that y
ou get a few. What you should do is to check out our literature suggestions at
 http://www.comeaucomputing.com/booklist as most of these books have withstood
 the test of time. Take the list with you to your favorite online or local tec
hnical bookstore. Take your time -- maybe an hour or more -- and browse the bo
oks for what looks right for you.
Note that we've broken our list down into categories, consider getting one or
two from each category. Some you should get as references, others you should g
et to read from cover to cover.

Note that often there is a problem between technical accuracy and readability.
 You may have a very readable book that's telling you wrong things, or avoidin
g fundamentals or insights, but that's won't get you anywhere to be reading th
e wrong things albeit easily. The converse is a very accurate book that is not
 as easy to read. There is a price to pay either way, but generally you're bet
ter off with the technically correct text. We believe this is so for the short
 and long term. And in general, please make an effort to avoid product oriente
d books, or books with titles that just make things sound like everything will
 just be so great.

Categorically, we have not been satisfied with online tutorials (this does not
 mean that there are no good ones, just that we have not seen it yet). If you
know of one that's excellent, don't hesitate to email us about it.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Where is the FAQ for the various C and C++ newsgroups?
Newsgroup FAQ URL
news:alt.comp.lang.learn.c-c++ NEW URL http://snurse-l.org/acllc-c++/faq.html

OLD URL http://www.faqs.org/faqs/C-faq/learn/
news:comp.lang.c
news:comp.std.c http://www.eskimo.com/~scs/C-faq/top.html
news:comp.lang.c++
news:comp.lang.c++.moderated NEW URL http://www.parashift.com/cpp-faq-lite/
OLD URL http://marshall-cline.home.att.net/cpp-faq-lite/
OLD URL http://www.cerfnet.com/~mpcline/c++-faq-lite
Welcome to comp.lang.c++ http://www.slack.net/~shiva/welcome.txt
news:comp.std.c++ http://www.jamesd.demon.co.uk/csc/faq.html
This document (The Comeau C++ and C FAQ) http://www.comeaucomputing.com/techta
lk
The Comeau C++ TEMPLATES FAQ http://www.comeaucomputing.com/techtalk/templates

The Comeau C99 FAQ http://www.comeaucomputing.com/techtalk/c99

In general, if you need a FAQ, check out http://www.faqs.org

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Can I really get the C++ Standard electronically for $18?
Can I get Standard C electronically too??
Yes, an electronic version of Standard C++ can be downloaded from ANSI for $18
. For details on getting Standard C++, please refer to our discussion at http:
//www.comeaucomputing.com/iso
The latest revision of Standard C, so-called C99, is also available electronic
ally too from ANSI. ANSI C89 or ISO C90 is still currently available but only
in paper form. For instance, Global Engineering Documents was carrying C89 (X3
.159). Once at that link, click US, enter "x3.159" in the document number (NOT
 the document title) search box, and that'll get you the latest info from Glob
al on this paper document (last we checked it was US$148)

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's wrong with code that uses void main()?
The following code is not usually considered correct:
// A: main should not return a void
void main() { /* ...Whatever... */ }
// AA: This is just the same as A:
void main(void) { /* ...Whatever... */ }
The problem is that this code declares main to return a void and that's just n
o good for a strictly conforming program. Neither is this:
// B: implicit int not allowed in C++ or C99
main() { /* ...Whatever... */ }

The problem with code example B is that it's declaring main to return nothing.
 But not declaring a function's return value is an error in C++, whether the f
unction is main or not. In C99, the October 1999 revision to Standard C, not d
eclaring a function's return value is also an error (in the previous version o
f Standard C an implicit int was assumed as the return value if a function was
 declared/defined without a return value). But the usual requirement of both S
tandard C++ and Standard C is that main should be declared to return an int. I
n other words, this is an acceptable form of main:

// C: Ok in C++ and C
int main(void) { /* ... */ }

Also, an empty parameter list is considered as void in C++, so this is ok in C
++:

// D: Ok in C++ and C
int main(/*NOTHING HERE*/) { /* ... */ }

Note that it is ok in Standard C too, because although there is an empty param
eter list, D is not a declaration but a definition. Therefore, it is not unspe
cified as to what the arguments are in C, and it is also considered as having
declared a void argument.

When you desire to process command line arguments, main may also take this for
m:

// E: Ok in C++ and C
int main(int argc, char *argv[]) { /* ... */ }

Note that the names argc and argv themselves are not significant, although com
monly used. Therefore F is also acceptable:

// F: Ok in C++ and C
int main(int c, char *v[]) { /* ... */ }

Similarly, array parameters "collapse" into pointer arguments, therefore, G is
 also acceptable:

// G: Ok in C++ and C
int main(int c, char **v) { /* ... */ }

The int return value may also be specified through a typedef, for instance:

// H: Ok in C++ and C
typedef int Blah;
Blah main() { /* ... */ }

Here, main is declared to return an int, since Blah is defined as an int. This
 might be used if you have system-wide typedefs in your shop. Of course, the f
ollowing is also allowed since BLAH is text substituted by the preprocessor to
 be int:

// I: Ok in C++ and C
#define BLAH int
BLAH main() { /* ... */ }

Do note though that the standards do not talk about all integers, but int, so
you wouldn't want to do these:

// J: Not ok
unsigned int main() { /* ... */ }

// K: Not ok
long main() { /* ... */ }

Often some of this can compound. For instance, a problem some run into looks a
s follows, consider:

#include "SomeHeader.h"
main()
{
/* ... */
}

However, note that Someheader.h is written like this:
struct WhatEver {
/* ... */
}
/* MISSING semicolon for the struct */

That means that the main in this case is being declared to return a WhatEver.
This usually results in a bunch of funny errors, at best.
In short, you wouldn't expect this to work:

// file1.c
float foo(int arg) { ... }

// file2.c
int foo(int);

But that's exactly the scenario that occurs when you misdeclare main, since a
call to it is already compiled into your C or C++ "startup code".
The above said, the standards also say that main may be declared in an impleme
ntation-defined manner. In such a case, that does allow for the possibility of
 a diagnostic, that is, an error message, to be generated if forms other than
those shown above as ok are used. For instance, a common extension is to allow
 for the direct processing of environment variables. Such capability is availa
ble in some OS's such as UNIX and MS-Windows. Consider:

// L: Common extension, not standard
int main(int argc, char *argv[], char *envp[])

That said, it's worth pointing out that you should perhaps favor getenv() from
 stdlib.h in C, or cstdlib in C++, when you want to access environment variabl
es passed into your application. (Note this is for reading them, writing envir
onment variables so that they are available after your application ends are tr
icky and OS specific.)

Last but not least, it may be argued that all this is not worth the trouble of
 worrying about, since it's "such a minor issue". But that fosters carelessnes
s. It also would support letting people accumulate wrong, albeit "small", piec
es of information, but there is no productive benefit to that. It's important
to know what is a compiler extension or not. There's ev to generate code that
crashes if the wrong definition of main is provided.

By the way, the above discussions do not consider so-called freestanding imple
mentations, where there may not even be a main, nor extensions such as WinMain
, etc. It may also be so that you don't care about whether or not your code is
 Standard because, oh, for instance, the code is very old, or because you are
using a very old C compiler. Too, note that void main was never K&R C, because
 K&R C never supported the void keyword. Anyway, if you are concerned about yo
ur code using Standard C++ or Standard C, make sure to turn warnings and stric
t mode on.

If you have a teacher, friend, book, online tutorial or help system that is in
forming you otherwise about Standard C++ or Standard C, please refer them to t
his web page http://www.comeaucomputing.com/techtalk. If you have non-standard
 code which is accepted by your compiler, you may want to double check that yo
u've put the compiler into strict mode or ANSI-mode, and probably it will emit
 diagnostics when it is supposed to.

Back to Top  Try Comeau C++ online at http://www.comeaucomputing.com/tryitout


------------------------------------------------------------------------------
--

What about returning from main()?
Semantically, returning from main is as if the program called exit (found in <
cstdlib> in C++ and <stdlib.h> in C) with the same value that was specified in
 the return statement. One way to think about this is that the startup code wh
ich calls main effectively looks like this:

// ...low-level startup code provided by vendor
exit(main(count, vector));

This is ok even if you explicitly call exit from your program, which is anothe
r valid way to terminate your program, though in the case of main many prefer
to return from it. Note that C (not C++) allows main to be called recursively
(perhaps this is best avoided though), in which case returning will just retur
n the appropriate value to wherever it was called from.

Also note that C++ destructors won't get run on ANY automatic objects if you c
all exit, nor obviously on some newd objects. So there are exceptions to the s
emantic equivalence I've shown above.

By the way, the values which can be used for program termination are 0 or EXIT
_SUCCESS, or EXIT_FAILURE (these macro can also be found in stdlib.h in C and
cstdlib in C++), representing a successful or unsuccessful program termination
 status respectively. The intention is for the operating system to do somethin
g with the value of the status along these same lines, representing success or
 not. If you specify some other value, the status is implementation-defined.


What if your program does not call exit, or your main does not return a value?
 Well, first of all, if the program really is expected to end, then it should.
 However, if you don't code anything (and the program is not in a loop), then
if the flow of execution reaches the terminating brace of main, then a return
0; is effectively executed. In other words, this program:

int main() { }

is effectively turned into this:

int main() { return 0; }

Some C++ compilers or C compilers may not yet support this (and some folks con
sider it bad style not to code it yourself anyway). Note that an implication o
f this is that your compiler may issue a diagnostic that your main is not retu
rning a value, since it is usually declared to return an int. This is so even
if you coded this:

int main() { exit(0); }

since exit is a library function, in which case you may or may not have to add
 a bogus return statement just to satisfy it.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Where does the int returned from main() go?
This depends upon your platform. And exactly what gets passed back to your env
ironment/operating system/etc. is implementation-defined. As mentioned above,
startup code written by your compiler vendor calls your main, and similarly, t
ermination code terminates your program.
An implementation-defined description follows. On UNIX, the low-order 8-bits o
f the int status are returned. Another process doing a wait() system call, whi
ch is not a Standard function, might be able to pick up the status. A UNIX Bou
rne shell script might pick it up via the shell's $? environment variable. MS-
DOS and MS-Windows are similar, where the respective compilers also have funct
ions such as wait upon which another application can obtain the status. As wel
l, in command line batch .BAT files, you can code something like IF ERRORLEVEL
..., or with some versions of Windows, the %ERRORLEVEL% environment variable.
Based upon the value, the program checking it may take some action.

Do note as mentioned above, that 0, EXIT_SUCCESS and EXIT_FAILURE are the port
able successful/unsuccessful values allowed by the standard. Some programs may
 choose to use other values, both positive and negative, but realize that if y
ou use those values, the integrity of those values is not something that the S
tandard controls. In other words, exiting with other than the portable values,
 let's assume value's of 99 or -99, may or may not have the same results/inten
tions on every environment/OS.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's the difference between endl and '\n'?
Folks often see output statements like the two below, and then want to know wh
at the difference is:
#include <iostream>

int main()
{
  int i = 99;
  std::cout << i << '\n'; // A
  std::cout << i << std::endl; // B
  return 0;
}

In short, using '\n' is a request to output a newline. Using endl also request
s to output a newline, but it also flushes the output stream. In other words,
the latter has the same effect as (ignoring the std:: for now):

cout << i << '\n'; // C: Emit newline
cout.flush(); // Then flush directly

Or this:

cout << i << '\n' << flush; // D: use flush manipulator

In a discussion like this, it's worth pointing out that these are different to
o:

cout << i << '\n'; // E: with single quotes
cout << i << "\n"; // F: with double quotes

In specific, note that Es last output request is for a char, hence operator <<
(ostream&, char) will be used. In Fs case, the last is a const char[2], and so
 operator <<(ostream&, const char *) will be used. As you can imagine, this la
tter function will contain a loop, which one might argue is overkill to just p
rint out a newline. Some of these same point also apply to comparing these thr
ee lines of code, which all output h, i and newline, somewhere in some way:

cout << "hi\n"; // G
cout << "hi" << '\n'; // H
cout << "hi" << "\n"; // I

By the way, although these examples have been using cout, it does not matter w
hich stream is being used. Also, note that line A may also cause a flush opera
tion to occur in the case where the newline character just happens to be the c
haracter to fill up the output buffer (if there is one, that is, the stream in
 question may happen to not be buffered).

In conclusion, which of these should you use? Unless performance is absolutely
 necessary, many favor using endl, as many find that just typing endl is in mo
st cases easy and readable.

Here's a bit more technical information for those so inclined. As it turns out
, endl is called an iostreams manipulator. In reality, it is a function genera
ted from a template, even though it appears to be an object. For instance, ret
aining its semantics, it might look like this:

inline ostream &std::endl(ostream& OutStream)
{
  OutStream.put('\n');
  OutStream.flush();
  return OutStream;
}

Iostreams machinery kicks in because it has an ostream& std::operator <<(ostre
am &(*)(ostream&)) which will provide a match for endl. And of course, you can
 call endl directly. In other words, these two statements are equivalent:

endl(cout);
cout << endl;

Actually, they are not exactly the same, however their observable semantics is
.

There are other standard manipulators. We leave it as an exercise to the reade
r to research how to create your own manipulator, or how to override something
 like endl.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Why can't I fflush(stdin), or any input stream?
How do I remove all chars from a stream?
Many beginners often write the following C program:
#include <stdio.h>

int main()
{
    /* Code using stdin inserted here */
    fflush(stdin); // eat all chars from stdin, allegedly
    /* More code using stdin */
}

But this won't work. It is undefined behavior because the standard only provid
es words to make sense out of fflush()ing output streams, not input streams. T
he reason this is so is because the stdio buffer and the operating system buff
er are usually two different buffers. Furthermore, stdio may not be able to ge
t to the OS buffer, because for instance, some OSs don't pass the buffer along
 until you hit return. So, normally, you'd either have to use a non-standard n
on-portable extension to solve this, or write a function to read until the end
 of the line.
In C++, you might do this:

#include <iostream>

int main()
{
    char someBuffer[HopeFullyTheRightSize];
    /* Code this and that'ing std::cin inserted here */
    /* Now "eat" the stream till the next newline */
    std::cin.getline(someBuffer, sizeof(someBuffer), '\n');
    /* More code using std::cin */
}

One problem here is that an acceptable buffer size must be chosen by the user.
 To get around this, the user could have used a C++ string:
#include <iostream>
#include <string>

int main()
{
    std::string someStringBuffer; // Don't worry about line length
    /* This and that'ing with std::cin here */
    std::getline(std::cin, someStringBuffer);
    /* More code using std::cin */
}

A problem still remain here in that the code still requires a buffer to be exp
licitly provided by the user. However, iostreams has capability to handle this
:
#include <iostream>
#include <limits>

int main()
{
    /* Code using std::cin inserted here */
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    /* More code using std::cin */
}

It might be worth wrapping that line up into an inline function, and letting i
t take a std::istream & argument:
inline void eatStream(std::istream &inputStream)
{
    inputStream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

Note that often you will see std::cin.clear() used, which may look redundant g
iven .ignore(). However, .clear() does not clear characters. Instead, it clear
s the respective stream's state, which is important to do sometimes. The two o
perations often go hand in hand because perhaps some error situation has occur
red, like reading a number when alphabetic characters are in the input stream.
 Therefore, often clearing the stream state and the bad characters is often do
ne in adjacent lines together, but be clear :), they are two different operati
ons.

Of course, you don't have to .ignore() the max possible number of characters,
but as many chars as you like, if less makes sense for the problem that you ar
e solving. The above shows C++ solutions, but C solutions will be similar, to
wit, you need to explicitly eat the extra characters too, perhaps:

#include <stdio.h>

void eatToNL(FILE * inputStream)
{
    int c;
    /* Eat till (& including) the next newline */
    while ((c = getc(inputStream)) != EOF)
       if (c == '\n')
           break;
}

/* blah blah */
eatToNL(stdin);
/* blah blah */

As usual, don't hesitate to read your texts on the functionality of iostreams
or stdio.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Is delete the same as delete []?
If you new an array, then you need to delete [] the array:
class Comeau { };
// ...
Comeau *p = new Comeau[99];
delete [] p; // ok
// ...
Comeau *p2 = new Comeau;
delete [] p2; // not ok

If you new a scalar, then you need to delete a scalar:
Comeau *p3 = new Comeau;
delete p3; // ok
// ...
Comeau *p4 = new Comeau[99];
delete p4; // not ok

The reason so is because delete doesn't just get rid of the memory, but runs t
he respective destructors for each element as well. This does not mean that si
nce builtin types don't have destructors that this is ok:
int *p5 = new int[99]; // AA
delete p5; // BB: NO!

It does not matter if violations of these points appears to work with your com
piler. It may not work on another compiler, or even an upgrade of the same com
piler, since the Standard has no such provision for line BB given line AA.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Why can't my compiler find cout, or anything from the Standard library?
What's std or std::?
What happened to .h suffixes on headers?
Is iostream.h ok?
Standard C++ supports something called namespaces, a way to logically organize
/categorize/modularize your programs. Since such abstraction capability is use
ful, the C++ Standard Library is placed into a namespace called std. That mean
s that when you do this:
#include <iostream>

int main()
{
    cout << "hello, world\n";
}

it may be an error, because there is no cout, there is a std::cout. So spellin
g it like that is one way to fix the above code:
std::cout << "hello, world\n";

You could also use a using declaration:
using std::cout; // read as: hey, cout is in now in scope
// Therefore, cout is a synonym for std::cout
//...
std::cout << "hello, world\n"; // ok no matter what
cout << "hello, world\n"; // ok because std::cout is in scope

You could also use a using directive:
using namespace std; // hey, all of std is in scope
//...
std::cout << "hello, world\n"; // ok no matter what
cout << "hello, world\n"; // ok because std::cout is in scope
                   // because all of std from the headers used is in scope

Although this is not a namespaces tutorial, it's worth pointing out that you s
hould usually consider putting your usings as local as possible. The reason wh
y is because the more usings that you use, the more you'll be defeating namesp
aces. IOWs, when possible:
Fully qualify a name.
When that's inappropriate, use a using declaration in as local scope as possib
le.
When that's inappropriate, use a using directive in as local scope as possible
.
A local scope includes a function, a class, even another namespace.
These points are true of the rest of the names in the standard library, whethe
r std::vector, or whatever... so long as you've #included the right header of
course:

#include <vector>
#include <string>

vector<string> X; // nope
std::vector<std::string> Y; // ok

Which brings up the issue that Standard C++ does not have a header named <iost
ream.h>, although many compilers support it for backwards compatibility with p
re-Standard implementations, where namespace didn't exist. So, as an extension
, the original example given in this section may work on some implementations
(with iostream.h or iostream).
Similarly, the Standard C headers, such as <stdio.h>, are supported in C++, bu
t they are deprecated. Instead, so-called Cname headers are preferred, for ins
tance, cstdio, or cctype instead of ctype.h Furthermore, names in the .h are a
ssumed to be in the global namespace, and so therefore do not need to be quali
fied with std::. The .h form is sometimes used as a transition model for backw
ards compatibility. Or, for a "co-ed" source file able to be compiled by a C o
r C++ compiler.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Why is an unnamed namespace used instead of static?
In C++, some uses of the static keyword have been deprecated. In particular, a
n unnamed namespace should be favored over some previous uses of "file scope s
tatic's". In fact in some cases an unnamed namespace must be used in order to
obtain a similar effect. That is to say, this code:
// x.cpp
static bool flag = false; // AAA

void foo() { if (flag)... }
void bar() { ...flag = true... }

should instead often be composed this way in C++:
// x.cpp
namespace /* NOTHING HERE!! */ { // BBB
    bool flag = false; // no need for static here
}

The use of static in AAA indicates that flag has internal linkage. This means
that flag is local to its translation unit (that is, effectively it is only kn
own by its name in some source file, in this case x.cpp). This means that flag
 can't be used by another translation unit (by its name at least). The goal is
 to have less global/cross-file name pollution in your programs while at the s
ame time achieving some level of encapsulation. Such a goal is usually conside
red admirable and so therefore is often considered desirable (note that the go
al, not the code, is being discussed in this sentence).

Contrast this to BBB. In the case of using the unnamed namespace above, flag h
as external linkage, yet it is effectively local to the translation unit. It i
s effectively still local because although we did not give the namespace a nam
e, the compiler generated a unique name for it. In effect, the compiler change
s BBB into this:

// Just get UNIQUE established
namespace UNIQUE { } // CCC
// Bring UNIQUE into this translation unit
using namespace UNIQUE;
// Now define UNIQUEs members
namespace UNIQUE {
    bool flag = false; // As Before
}

For each translation unit, a uniquely generated identifier name for UNIQUE som
ehow gets synthesized by the compiler, with the effect that no other translati
on unit can see names from an unnamed namespace, hence making it local even th
ough the name may have external linkage.
Therefore, although flag in CCC has external linkage, its real name is UNIQUE:
:flag, but since UNIQUE is only known to x.cpp, it's effectively local to x.cp
p and is therefore not known to any other translation unit.

Ok, so far, most of the discussion has been about how the two provide local na
mes, but what are the differences? And why was static deprecated and the unnam
ed namespace considered superior?

First, if nothing else, static means many different things in C++ and reducing
 one such use is considered a step in the right direction by some people. Seco
nd to consider is that names in unnamed namespaces may have external linkage w
hereas with static a name must have internal linkage. In other words, although
 there is a syntactic transformation shown above between AAA and BBB, the two
are not exactly equal (the one between BBB and CCC is equal).

Most books and usenet posts usually leave you off about right here. No problem
 with that per se, as the above info is not to be tossed out the window. Howev
er, you can't help but keep wondering what the BIG deal some people make about
 unnamed namespaces are. Some folks might even argue that they make your code
less readable.

What's significant though is that some template arguments cannot be names with
 internal linkage, instead some require names with external linkage. Remember,
 the types of the arguments to templates become part of the instantiation type
, but names with internal linkage aren't available to other translation units.
 A good rule of thumb to consider (said rather loosely) is that external names
 shouldn't depend upon names with less linkage (definitely not of those with n
o linkage, and often not even with names of internal linkage). And so it follo
ws from the above that instantiating such a template with a static such as fro
m AAA just isn't going to work. This is all similar to why these won't work:


template <const int& T> struct xyz { };

int c = 1;
xyz<c> y; // ok
static int sc = 1; // This is the kicker-out'er above
xyz<sc> y2; // not ok


template <char *p> struct abc { };

char comeau[] = "Comeau C++";
abc<comeau> co; // ok
abc<"Comeau C++"> co2; // not ok


template <typename T> struct qaz { };
void foo()
{
    char buf[] = "local";
    abc<buf> lb; // not ok
    static char buf2[] = "local";
    abc<buf2> lb2; // not ok

    struct qwerty {};
    qaz<qwerty> dq; // not ok
}

Last but not least, static and unnamed namespaces are not the same because sta
tic is deficient as a name constrainer. Sure, a C programmer might use it for
flag above, but what do you do when you want to layer or just encapsulate say
a class, template, enum, or even another namespace? ...for that you need names
paces. It might even be argued that you should wrap all your files in an unnam
ed namespace (all the file's functions, classes, whatever) and then only pull
out the parts other files should know about.

Draw your attention to that that none of the above is equal to this:

// x.cpp
namespace { // DDD
    static bool flag = false;
}

(The point of showing DDD is that you really wouldn't want to say it. I guess
one could say that it is redundant, and really just brings all the above issue
s right back (as in this flavor, it's not external). So, it's only shown to ma
ke sure you see that none of the previous versions look like this :).
Note that namespaces containing extern "C" declarations are in some ways as if
 they were not declared in the namespace, so since an unnamed namespace is a n
amespace, this holds true for an unnamed namespace as well.

Note also that the above discussion does not apply to the other uses of static
: static lifetime, static members or to static locals in a function.

Back to Top  Have you checked out Comeau C++ lately?

------------------------------------------------------------------------------
--

Why does C++ allow unnamed function parameters?
In C++, you can do this:
void foo(int /*no name here*/)
{
    // code for foo
}

Take note that although an int argument would be passed, it is not named. Why
would you do that? One reason is to "stub out" a routine. For instance, let's
say that some functionality was removed from an already existing program. Inst
ead of finding all calls of foo and removing them, they can be left in. The ef
fect is to no-op the code. If the function is inline defined, it wouldn't even
 generate any code.
Of course, this doesn't depend upon functions with just one argument. For inst
ance, you might have:

void bar(int arg1, int arg2, int arg3)
{
    // code for bar, using arg1, arg2 and arg3
}

Now let's say that the functionality of the program changes and that arg2 is n
o longer needed. Well, obviously you'll remove the code that uses arg2. But no
w the problem is that you'll probably get an "unused identifier" warning from
your compiler. To get rid of the warning you could give it a dummy value or us
e within the function, but that'll just confuse the issue. Instead, you can ju
st remove the argument name too:
void bar(int arg1, int /* Now unnamed */, int arg3)
{
    // code for bar, using arg1 and arg3
}

Sometimes though, the above approach is not just used to support legacy code,
but also to make sure an overloaded function gets picked, perhaps a constructo
r. In other words, passing an additional argument just to make sure a certain
function gets picked. As well, during code development it might help to use an
 unnamed argument if, for instance, you write stubs for some routines.
When possible, it probably should be argued that unused parameters should be r
emoved completely both from the function and from all the call points though,
unless your specifically trying to overload operator new or something like tha
t.

Also, note that the above discussion has no relation to code such as:

void function(int arg, ...);

which uses to the ellipsis notation (the dot dot dot) to specify that the argu
ments to a function are unspecified. These are unnamed too, but it establishes
 variable arguments to a function (which C supports too), and that's something
 else altogether.
Back to Top  Have you checked out Comeau C++ lately?

------------------------------------------------------------------------------
--

What are header file "include guards"?
What are header file "code wrappers"?
In a multi-source file project, it is reasonable to partition logically unique
 modules into separate physical header files. For instance, imagine the follow
ing 3 header files:
// a.h:
// ...
#include "xyz.h"
// ...

// b.h:
// ...
#include "xyz.h"
// ...

// xyz.h:
class xyz { };

Now, if you were to use some of these headers:
// main.c
#include "a.h"
#include "b.h"
// ...

then xyz.h will inadvertently be brought in twice, once by a.h and once by b.h
. This is a problem because then xyz will end up being defined twice in the sa
me translation unit, and it is an error to define the body of a class twice li
ke that. This situation is by no means unique to just classes though, and is a
s true for duplicate definitions of structs, enums, inline functions, etc.
To get around this, in both C++ and in C, a common code technique is to sandwi
ch the header file's source code with an #ifndef preprocessor directive. Consi
der a revised xyz.h:

// xyz.h:
#ifndef XYZ_H
#define XYZ_H

class xyz { };

#endif

With this revision, if xyz.h is #included, and the XYZ_H macro is not yet defi
ned, then it will #define it, and then it will inject the rest of the header f
ile's code into the translation unit, in this case, the code is the definition
 of class xyz. However, if XYZ_H has already been macro defined, then the prep
rocessor will skip to the #endif, and in effect will not inject, or re-inject,
 class xyz into the translation unit. This technique establishes the notion of
 include guards.
Look back at main.c. We see that xyz.h will be included through a.h and since
XYZ_H is not yet defined, it will define it and also let the compiler see the
class xyz definition. Now, when it moves to b.h, it will open xyz.h but since
it was already brought in by a.h, then XYZ_H is already macro defined. Therefo
re, it will skip right down to the #endif and the preprocessor will close b.h.


In effect, the second #include of xyz.h was skipped. Do note though that it di
d need to open it, process it only to see that it didn't need to do anything w
ith it, and then close it.

As shown above, the traditional naming of the macro is just to follow suite wi
th _H as a prefix to the file name. Do try to make the name unique, or maybe e
ven long'ish in some cases, in order to avoid name clashes with it though. As
well, avoid a name that will begin with an underscore, as most of those names
are reserved for compiler vendors.

Given all this, it's easy to consider that you can just start including header
s all over the place without any concerns. Clearly though, this can impact com
pile-time, and so you want to remain judicious in the headers you include. As
well, some compilers support pre-compiled headers, but this should not be an e
xcuse to get carried away.

It should be clear by now that you would add include guards for a.h and b.h to
o. Lastly, there are times even when you want to do this:

// abc.h
#ifndef ABC_H
#define ABC_H

#ifndef XYZ_H
#include "xyz.h"
#endif

#endif

Here, abc.h actually tests the macro from xyz.h before even trying to include
it. This avoids it from even being opened, but only if it's already been proce
ssed.
There's an implication here then that you can "fool a header", by #defineing t
he respective macro for it, so that perhaps it may not end up getting processe
d even once. Similarly, you can #undef the respective macro once the header ha
s been processed. As with many of the above remarks, make sure that's really w
hat you want to do.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How can two struct/classes refer to each other?
This problem takes many different flavors, but the general issues goes like th
is:
struct xyz {
    struct abc Abc; // AA
};
struct abc {
    struct xyz Xyz; // BB
};

Unfortunately, for this to work, struct abc needs to be moved before xyz, or e
lse, how could line AA work? But wait! That would mean xyz needs to be moved b
efore abc making this circular. One way around this is:
struct abc; // CC

struct xyz {
    struct abc* Abc; // DD
};
struct abc {
    struct xyz* Xyz; // EE
};

Here, we've changed Abc and Xyz into pointers. As well, we've forward declared
 abc in line CC. Therefore, even though abc has still not been defined, only d
eclared, that enough to satisfy the pointers, because there is not yet any cod
e which is going to be dereferencing the pointers, and by the time there is, b
oth struct will have been defined.
Of course this new design implies having to dynamically allocate the memory th
ese pointers will point to... unless of course, the self references are throug
h C++ references, which are possible. Here's a toy example:

struct abc; // CC

struct xyz {
    struct abc& Abc; // DD
    xyz();
};
struct abc {
    struct xyz& Xyz; // EE
    abc();
};

xyz::xyz() : Abc(*new abc) { }
abc::abc() : Xyz(*new xyz) { }

Of course, in this last example, the way the constructors are set up would est
ablish an infinite loop, so you need to be careful when using self-referrentia
l classes. In other words, you would probably normally not do it like the exam
ple above shows, and depending upon your specifics may have to change your des
ign.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's the scope of a for loop declaration?
C++ allows identifiers to be declared in for loops. For instance, consider num
sides in line A below. In pre-Standard C++ specifications, the scope of such a
n identifier continued to the end of the block that the for loop was declared
in. Therefore, to be able to interrogate numsides on line B was ok under those
 rules.
#include <iostream>
int main()
{
  const int maxsides = 99;
  for (int numsides = 0; numsides < maxsides; numsides++) { // A
    if (...SomeCondition...)
      break;
    // blah blah
  }
  if (numsides != maxsides) // B
    std::cout << "Broke out of loop\n";
  return 0;
}

However, toward the end of the standardization process, related to some other
rules (about conditional declarations in general), the committee decided that
the scope of the identifier should only be within the for, therefore, line B i
s an error accto Standard C++. Note that some compilers have a switch to allow
 old style code to continue to work. For instance, the transition model switch
 is --old_for_init under Comeau C++. In order for line B to work under Standar
d C++, line A needs to be split into two lines:

int numsides;
for (numsides = 0; numsides < maxsides; numsides++) { // revised line A

Here numsides is in scope till the end of its block, having nothing to do with
 the for as far as the compiler is concerned, which is "as usual". And of cour
se, you can always introduce another brace enclosed block if you want to const
rain the scope for some reason:

// ...code previous...
{
  int numsides;
  for (numsides = 0; numsides < maxsides; numsides++) {
    // ...
  } // end of for loop
} // scope of numsides ends here
// .. rest of code...

Finally, consider this code:

#include <iostream>
int numsides = 999; // C
int main()
{
  const int maxsides = 99;
  for (int numsides = 0; numsides < maxsides; numsides++) {
    if (...SomeCondition...)
      break;
    // blah blah
  }
  if (numsides == maxsides) // B: refers to ::numsides
    std::cout << "Broke out of loop\n";
  return 0;
}

Here, line B is ok because although the local numsides from the for loop is ou
t of scope, it turns out that the global numsides from line C is still availab
le for use. As a QoI (Quality of Implementation) issue, a compiler might emit
a warning in such a case. For instance, Comeau C++ generates the following dia
gnostic when --for_init_diff_warning is set:

warning: under the old for-init scoping rules
variable "numsides" (the one declared at line 2) --
would have been variable "numsides" (declared at line 6)

Too, try to name your identifiers better, and perhaps they will have less chan
ce of clashing like this anyway. Also, in some cases, you may have code someth
ing like this:

  for (int numsides = 0; numsides < maxsides; numsides++) // D
    ;
  // numsides should be out of scope here

  // create another, different, numsides
  for (int numsides = 0; numsides < maxsides; numsides++) // E
    ;

The numsides from line D can not be in scope in order for line E to work. Whic
h is fine with Standard C++, as it won't be. However, you may be using it with
 a compiler that doesn't support the proper scoping rules, or for some reason,
 has disabled them. As a short term solution, you may want to consider the fol
lowing hackery (think about how it'll limit the scope):

#define for if(0);else for
Depending upon your compiler, these forms may or may not be better:
#define for if(0) { } else for
#define for if(false) { } else for

Of course, technically, as per Standard C++, redefining a keyword is illegal,
but few compilers (if any) will actually diagnose this as a problem.
As well, for a totally different take on the subject, as shown slightly differ
ent above, you can add an extra set of braces around the code

  { for (int numsides = 0; numsides < maxsides; numsides++) // F
    ;
  }
  { for (int numsides = 0; numsides < maxsides; numsides++) // G
    ;
  }

You can also of course add additional identifiers:
  for (int numsides = 0; numsides < maxsides; numsides++) // H
    ;
  for (int numsides2 = 0; numsides2 < maxsides; numsides2++) // I
    ;

None of these are optimal for normal code and perhaps not even good short term
 solutions, but if you have an old compiler, you may have no choice.
Back to Top  Have you seen the Comeau C++ features list lately?

------------------------------------------------------------------------------
--

What does for(;;) mean?
Informally a for loop has three parts you can specify:
A so-called initialization, performed at loop start up. This is often an assig
nment statement. In C++ it can also be a declaration (see the previous topic a
bove just before this one for an example).
A condition, to be tested before each iteration of the loop. If the condition
is false, the loop is terminated.
An expression, which gets executed at the end of each iteration of the loop. T
his is often an increment.
Any, or all, of these parts can be left out. In the case of the initialization
 part, perhaps some other code elsewhere will do it, or perhaps it's been set
up earlier. In other words, this might be ok:
// ...
int counter;
// ...
// counter set by some other code somehow
// ...
for (/* nothing here */; counter < SomeMaxValue; counter++) {
    // ...
}

Also, perhaps the last expression is complex, and therefore you may want to pu
t its computation into the body of the loop, etc. So, perhaps you might have:

// ...
int counter;
// ...
for (counter = 0; counter < SomeMaxValue; /* nothing here */) {
    // ...
    // elaborate formula to calculate the next value of counter
    // ...
}

This middle condition can also be missing, upon which it is taken as true. So
unless specified elsewhere, this loops forever:
for (int counter; /* nothing here */; counter++) {
    // ...
    // Perhaps this loop has a test here, and executes a "break;"
    // ...
}

In the case where all are missing, as in for(;;), it also establishes an infin
ite loop. Here too, some other code would be necessary to break out of it, unl
ess of course the app is intended to run continuously:
int main()
{
    for ( ; ; ) {
        // ...
        // Perhaps this loop has a test, and eventually hits a "break;"
        // or Perhaps it really does loop forever
        // ...
    }
}

As an aside, it's worth considering that this:
for (xxx; yyy; zzz) {
    aaa;
}

can be trivially thought of as this:
{
    xxx;
    while(yyy) {
        aaa;
        zzz;
    }
}

We say trivially because we are not trying to say every for loop can be so eas
ily transformed into such a while loop so directly. For instance, if the code
in aaa contains a continue statement, then zzz will be executed in the for loo
p but not in the while loop.
Also, too, it's worth pointing out that the while loop was placed into a block
. See #forinit in this FAQ for why.

Note the following infinite loops:

for(;;).....
for(; 1; )....
for(; 1 == 1; )....
for(; true; )... // in C++
while(1)....
while(1 == 1)....
while(true)... // in C++
do .... while(1);
do .... while(true); // in C++
label: ... goto label;

The first is probably the most common form seen, though now that C++ and C99 h
ave booleans, that may be changing.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's the difference between #define and const?
Why is the preprocessor frowned upon?
There are a few problems with #define in C and C++, whether the macro is being
 used as a named constant or as a function-like entity. Among them include:
The preprocessor is effectively a separate language from C or C++, and so at s
ome level the compiler really knows nothing about what happened. In effect, th
e text substitutions that occur happen before the so-called compiler proper ph
ase is invoked.
Macros have their own scopes.
Macros can produce unplanned for side-effects.
Macros have no type, they are "just text".
You cannot take the address of a macro.
The debugger, error messages, etc. usually know nothing about macros.
Therefore, it's common that the preprocessor should be avoided for some things
. However, there are some alternatives to macros that are often superior and t
hey include:
consts, which are types
enums, which allow distinct related "sets" of constants
inline functions, which obey C++ (and now C99) function semantics
templates, in C++
Of course, this is not to imply all uses of the preprocessor should be avoided
. For instance, although #include is a rather weak mechanism, it's at least su
fficient. Similarly, #ifdef and friends have their place.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How do I clear the screen?
How do I change the color of the screen?
How does one erase the current line...And questions like these?
Neither Standard C nor Standard C++ provide such a capability. It is considere
d beyond their scope due to the diversity in operating systems, since a screen
 or terminal or monitor or console might not even exist, etc.
That being so, many compilers, or operating systems, do support an extension i
n order to be able to clear the screen, or erase the current line. For instanc
e, with Borland, you might do this:

#include <conio.h>
// ...
clrscr();

For some versions of Microsoft, you might do this:

#include <conio.h>
// ...
_clearscreen(_GCLEARSCREEN);

One of these will also often work on some systems:

#include <stdlib.h>
// ...
system("cls"); // For Dos/Windows et al "console app"
system("clear"); // For some UNIX's, LINUX, etc.
system("tput clear"); // For some UNIX's
// ...

effectively running the command in quotes as a process. Tied in with this, you
 could also create a shell script named cls which internally will do the clear
 or tput clear, and so on. Note that <stdlib.h> might be <cstdlib> in the case
 of C++, and so therefore references to system() above would be std::system().


You can also just output a known number of newlines in some cases, if you know
 the number:

// ...
const int SCREENSIZE = ???;
for (int i = 0; i < SCREENSIZE; i++)
    // output a newline, perhaps with std::cout << '\n';
// flush the output, perhaps with std::cout.flush();

You can also just hard-code an escape sequence, though this too may not be por
table:
std::cout << "\033[2J" << std::flush;

This of course means too that something like this could be done in VC++ as wel
l:
#include <conio.h>
// ...
_cputs("\033[2J");

There is also the "curses" (or ncurses in some cases) system, which, although
not Standard, was popular with UNIX before X-windows became popular:
#include <curses.h>

int main()
{
    initscr(); // set up a curses window
    clear(); // clear the curses window
    refresh(); // commit the physical window to be the logical one

    // stuff using the window

    endwin();
    return 0;
}

and/or various different graphics and windowing systems, etc.
If it's not obvious to you yet, whether you're clearing the screen, erasing th
e current line, changing the color of something, or whatever, you'll need to c
oncede that no one way is portable, and that to accomplish what you need you'l
l have to find a platform specific solution in most cases. Check with your com
piler or operating system vendor's documentation for more details. And never d
iscard ingenuity when it's necessary. For instance, on some displays you may g
et away with emitting a form feed, or a special escape sequence. Or, if you ha
ve a primitive device you may have to do something like figure out how many ne
wlines/spaces/tabs/whatever, to emit in order to scroll the screen away, thoug
h the cursor may not be where you prefer it. And so on.

Last but not least, construct your code sensibly. If you really do need say th
e ability to clear the screen, don't lace system dependent calls through your
code, or even #ifdefs. Instead, write a function to encapsulate the call, so t
hat if you do need to localize it in some way, at least it's just in one place
.

Back to Top  Check out Comeau C++ here

------------------------------------------------------------------------------
--

How do I read just one character, w/o a return?
Neither Standard C nor Standard C++ provide such a capability. It is considere
d beyond their scope due to the diversity in operating systems, input devices,
 etc. For instance, this:
#include <stdio.h>
// ...
getchar(); // Wait for any character to be hit

may not work because often input is first processed by your operating system a
 line at a time by default. This means, in those cases, that although the getc
har() might be executing it won't be satisfied until the operating system pass
es its buffer to your program, upon which stdio will pass it to getchar(). Sec
ond, even if your OS is placed into a "raw" mode (assuming the OS even allows
that), processing a char at a time, the stdio input stream being used might be
 in a buffered mode, therefore it would need to be made unbuffered, via say se
tbuf() (setting setbuf alone w/o raw mode may be insufficient).
Some compilers do support an extension in order to be able to get one characte
r from a stdio input stream. For instance, on some Windows' compilers, you mig
ht do this:

#include <conio.h>
// ...
getch(); // NOT standard, NOT in stdio
getche(); // same as getch() but echo's the char to display device

Everything above is true about iostreams in C++ as well, although it would use
 different input routine names, etc.
Final note: before getting too carried away with this, but sure you actually n
eed such a capability. That is, often it's as handy to get a whole line, waiti
ng for return to be entered. So, just make sure you know what you want and/or
what is acceptable.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How to convert a char array or C++ string to an int?
The classic C solution is to use the C Standard library:
#include <stdlib.h>
// ...
const char array[] = "99";
int x = atoi(array); // convert C-style string to int

Standard C also supports some other conversion function. We'll show it using C
++ style headers for a C++ program though (a C program would continue to use s
tdlib.h):
#include <cstdlib> // Use C++ style header
// ...
const char xyz[] = "99";
const char abc[] = "99.99";
int x = atoi(xyz); // convert C-style string to int
// Note: atof returns a double, not a float
double x = atof(abc); // convert C-style string to float
long x = atol(xyz); // convert C-style string to long
// long long and atoll is new in C99, the 1999 revision to Standard C
long long x = atoll(xyz); // convert C-style string to long long

Note that if you pass an invalid number to any of these functions, the result
is undefined behavior, ditto for if the value will be too big for the resultin
g type:
int x = atoi("999999999999999999"); // Undefined (if int cannot hold that valu
e on your machine)
int y = atoi("Use Comeau C++"); // ok: results in 0
int z = atoi("  99"); // ok: results in 99
int e = atoi("-99"); // ok: results in -99

For exposition purposes, take note of the following "equivalences" (except for
 error handling): atof strtod(nptr, (char **)NULL)
atoi (int)strtol(nptr, (char **)NULL, 10)
atol strtol(nptr, (char **)NULL, 10)
atoll strtoll(nptr, (char **)NULL, 10)
These strto... routines are also in stdlib.h. Furthermore, although there is n
o corresponding ato... versions for the following, there is also: strtoul/stri
ng to unsigned long, strtoull/string to unsigned long long, and also these, ad
ded new in C99: strtof/string to float, strtold/string to long double, strtoim
ax/string to intmax_t, and strtoumax/string to uintmax_t
Although much legacy code uses the ato... versions, and an implementation migh
t have faster ato... versions, it's also true that the interface to the strto.
.. version are more flexible, reliable and with more control possible. As such
, we encourage you to investigate these routines. There are also wide string v
ersions of all the above too. Since the atoi.. versions pass a null pointer as
 the "end pointer", here's a quick example that actually uses it with a "real"
 end pointer argument:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
  char someBuffer[] = "1234";
  char someOtherBuffer[] = "1234s";
  char *endptr;
  long l;

  l = strtol(someBuffer, &endptr, 10);
  if (endptr == &someBuffer[strlen(someBuffer)])
    printf("SomeBuffer %s was a number\n", someBuffer);
  else
    printf("SomeBuffer %s was NOT a number\n", someBuffer);

  l = strtol(someOtherBuffer, &endptr, 10);
  if (endptr == &someOtherBuffer[strlen(someOtherBuffer)])
    printf("SomeOtherBuffer %s was a number\n", someOtherBuffer);
  else
    printf("SomeOtherBuffer %s was NOT a number\n", someOtherBuffer);

  return 0;
}

Do read up on these routines since they have other capabilities (allowing plus
, minuses, spaces, etc.).
Do not forget the "String I/O" routines either. For instance:

#include <stdio.h> // cstdio in C++
// ...
int return_status;
int x;
double d;
return_status = sscanf(xyz, "%d", &x);
// ...
return_status = sscanf("99.99", "%f", &d);

Perhaps abstracting this into a function of your own naming. You'll need to we
igh the impact of bringing in all of sscanf, making sure you use the &, etc. T
here is also a similar situation with "String Streams I/O" in C++:
#include <sstream>
// ...
char carray[] = "99";
std::istringstream buffer(carray);
int x;
buffer >> x;
// ...
#include <string>
std::string str("-99.99");
std::istringstream FloatString(str);
float f;
FloatString >> f;

You can also convert a C++ string in other ways too, for instance:
#include <cstdlib>
#include <string>
inline int stoi(std::string &s)
{
    return std::atoi(s.c_str());
}

//...
int i = stoi(str);

And so on. Of course in all situations above, you should check error situation
s as appropriate.
Back to Top  World Class Comeau Compilers: Breathtaking C++, Amazing C99, Fabu
lous C90.

------------------------------------------------------------------------------
--

How to convert an int to a char array or C++ string?
Unlike routines like atoi mentioned in the previous question, there is no dire
ct routine such as itoa available. However, similar to the string I/O routines
 in the previous question, one can do this:
#include <stdio.h> // cstdio in C++
// ...
char buffer[N]; // Use a buffer of the appropriate size for N!!
                // Again: Use a buffer of the appropriate size for N!!
int x = 99;
sprintf(buffer, "%d", x);

If you were to wrap this into a routine, you'd need to either pass in the buff
er, dynamically allocate it (realizing that it would need to be deallocated by
 the calling code somewhere), or use statically allocated space internal to th
e function (which would need to be copied). It might also be handy to have ano
ther argument which specifies the base that the string form of the number shou
ld be written in.
In the "new" version of C, C99, there is another function which can help:

// ...
snprintf(buffer, N, "%d", x);
// ...

Notice this routine name has the letter n in it. It's different from sprintf i
n that any characters beyond N - 1 are thrown away. In other words, the buffer
 won't overflow. Note: Your C compiler may not yet support this routine.
In C++ you might also have:

#include <sstream>
// ...
std::ostringstream buffer;
buffer << x;

(And as a side remark, you can clear the ostringstream to reuse it by doing th
is:
// buffer contains value of x from above
buffer << y; // buffer contains xy
buffer.str(""); // 'clear' the buffer
buffer << y; // buffer contains y

Note the empty string literal).
So you might write yourself a handy routine:

#include <sstream>
#include <string>

std::string itos(int arg)
{
    std::ostringstream buffer;
    buffer << arg; // send the int to the ostringstream
    return buffer.str(); // capture the string
}

To use it you might have:
// ...
int x = 99;
std::string s = itos(x);
// ...

For that matter, you can do this for any type:
#include <sstream>
#include <string>

template <typename T>
std::string Ttos(T arg)
{
    std::ostringstream buffer;
    buffer << arg; // send the int to the ostringstream
    return buffer.str(); // capture the string
}

// ...
std::string s = Ttos(99.99);
std::string t = Ttos(99L);

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How to convert a string to a char *?
This question deals with Standard C++'s string class. Please note that this is
 wrong:
#include <string>

int main()
{
    std::string ComeauCpp("Check out Comeau C++");
    char *p = ComeauCpp; // nope
}

To wit, there is no conversion from string to char *. Some folks would try to
"correct" this by doing this:
char *p = &ComeauCpp; // If at first you don't succeed, try, try, again

But this is wrong too, because there is no conversion from string * to char *.
 As if two wrongs were not enough, some would still try to correct this as:
char *p = (char *)&ComeauCpp; // If two wrong's don't make a right, try three


under that premise that there was now a char * on either side. The problem her
e is that this assumes that the string class is implemented with a char array
buffer, which may not be true. And even if it were, it assumes that the buffer
 is at the start of the string class, not to mention a violation of encapsulat
ion. The right way to do this is to use strings conversion feature, its member
 function c_str(). For instance:
const char *p = ComeauCpp.c_str(); // Aha!

Note that you cannot alter the C-string "returned":
*p = 'X'; // Nope

and non-const string operations may invalidate it:
ComeauCpp.length(); // ok
ComeauCpp += "now!"; // may invalidate, so ASSUME IT DOES

Therefore, you should usually make use of the pointer immediately, and without
 string related side-effects. If the C-style string is something that you want
 to "hang around" and be used by other parts of your program, you can call c_s
tr() again when you need it (which may mean its value may be changed). Or you
may want to take a snapshot of its current value and therefore you'll need to
make a copy of it in that case. For instance, you might do this:
char *p = new char[ComeauCpp.length() + 1];
strcpy(p, ComeauCpp.c_str());

It might be handy to "wrap" this up into a helper function:
char *GetCString(std::string &s) { /* ... */ }

realizing it will be your responsibility to delete [] the memory that you new
[]d when you are done with it. Do not ever delete[] the pointer returned from
c_str() though, as that memory is "owned" by the string class.
You can also use the copy() operation from the string class if you don't want
to use routines such as strcpy(). For instance:

#include <string>

char *ToCString(std::string &s)
{
    char *cString = new char[s.length() + 1];
    s.copy(cString, std::string::npos); // copy s into cString
    cString[s.length()] = 0; // copy doesn't do null byte

    return cString;
}

int main()
{
    std::string hello("hello");
    // ...
    char *p = ToCString(hello); // AA: copy the std::string
    CallSomeCRoutineForInstance(p); // ok: p points to a copy
    // ... Modify hello below, no problem, that is
    // " world\n" DOES NOT effect p, since it's been copied already
    hello += " world\n";
    // passing p is ok
    // (it's pointing to the same C-string from line AA)
    CallSomeCRoutineForInstance(p);
    // ...
    delete [] p; // Our ToCString new[]d it, so...
}

And so on.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Why does C++ have a string when there is already char *?
How does C++'s string differ from C's?
Just like there are some differences between char [?] and char *, there are al
so differences between them and C++'s std::string class. In short, with a C-li
ke string you often need to worry about:
Routines such as strcpy() and strcat(),
Buffer sizes
Memory allocation
Etc.
With std::string, you usually don't need to worry about those things. Therefor
e, often std::string makes things:
Less error prone,
Easier to use,
Easier to teach
Consider this comparison:
// The "C way":
#include <cstring> // <string.h> in C
#include <cstdlib> // <stdlib.h> in C

void TheCishWay()
{
    char *s; // usually needs a pointer
    s = std::malloc(???); // enough space allocated?
                     // did you add +1 bytes for the null byte?
    std::strcpy(s, "hello");
    std::strcat(s, " world"); // did this overflow the space allocated?

    if (std::strcmp(s, "hello worlds") == -1)....

    std::free(s); // don't forget to delete the memory somewhere
}

// The "C++ way":
#include <string>
void TheCppishWay()
{
    std::string s;
    s = "hello";
    s += " world";

    if (s < "hello worlds")....

    std::string s2 = s + "\n";
}

On this same note, but more generally, don't hesitate to make use of C++'s std
::vector. As well, there are no null pointer std::strings, so "std::string ess
;" establishes an empty string not a null pointer.
Of course, sometimes you have no choice as to whether you want a C++ or a C st
ring. For instance, perhaps you are dealing with fragile legacy code. Or, perh
aps, you need to use command line arguments, you know, argv from int main (int
 args, char **argv). The above is also not to say that one can't have involved
 code in C++ using std::string, you can.

One question that arises about the differences is: Which should one use if a c
onst string is desired? Well, consider what it means. It implies no modificati
on, and so it will either be copied, inspected, or output. Well, it seems ther
e are three choices:

const char *one = "Comeau C++";
const char two[] = "Comeau C++"
const std::string three = "Comeau C++";

One might say the purest of one and two is two since it truly declares a named
 array. This might be handy if you just want to output it as a message or some
thing. And if you want to traverse it with pointer arithmetic or something, yo
u may want to add:
const char *ps;
// ...
ps = two;
// ..
ps++;
// ...

The issue with one is that the string literal is an unnamed array, and one is
made to point to it. This means the array and the pointer needs to exists. Thi
s is different from two and ps because two is still the array, whereas once yo
u do say one++ you've lost the pointer to the string literal. In other words,
to use one in the same way, you'd normally still need ps:
ps = one;
// ...
ps++;
// ...

So in common use, when const, in general, prefer the real array when possible.
 That leaves the general choice between two and three. Well, what can be said
of const std::strings?
They can be directly initialized with a C string:
const std::string comeau = "Comeau C++";

They can be directly copied:
const std::string morecomeau(comeau);

They require more involved library support, implying possibly larger executabl
es.
Operations such as find and find_first_of seem more natural.
Passing them to a routine requiring a C string requires using the c_str() oper
ation (this is true in the non-const case too though).
Length computation needs to occur at runtime (again, this is true of the non-c
onst case too, and in some C string cases too).
See #stringtostring for additional considerations.
So which you want in the const case should be based on criteria such as this.


Back to Top  Wow, Comeau C++ is available on so many platforms, CHECK IT OUT!


------------------------------------------------------------------------------
--

What's the difference between member initializing and assignment while constru
cting?
First of all, be clear on what "member initializing" is. It is accomplished th
rough a member initializer list. It is "spelled" by putting a colon and one or
 more constructor style initializers after the right parenthesis of the constr
uctor:
struct xyz {
    int i;
    xyz() : i(99) { } // Style A
};

xyz x;

will initialize x.i to 99. The issue on the table here is what's the differenc
e between that and doing this:
struct abc {
    int i;
    abc() { i = 99; } // Style B
};

Well, if the member is a const, then style B cannot possibly work:
struct HasAConstMember {
    const int ci;
    HasAConstMember() { ci = 99; } // not possible
};

since you cannot assign to a const. Similarly, if a member is a reference, it
needs to be bound to something:
struct HasARefMember {
    int &ri;
    HasARefMember() { ri = SomeInt; } // nope
};

This does not bind SomeInt to ri (nor does it (re)bind ri to SomeInt) but inst
ead assigns SomeInt to whatever ri is a reference to. But wait, ri is not a re
ference to anything here yet, and that's exactly the problem with it (and henc
e why it should get rejected by your compiler). Probably the coder wanted to d
o this:
struct HasARefMember {
    int &ri;
    HasARefMember() : ri(SomeInt) { }
};

Another place where a member initializer is significant is with class based me
mbers:
struct SomeClass {
    SomeClass();
    SomeClass(int);
    SomeClass& operator=(int);
};

struct HasAClassMember {
    SomeClass sc;
    HasAClassMember() : sc(99) { }
};

It is preferred over this:
HasAClassMember::HasAClassMember() { sc = 99; } // AAA

because the code for the assignment operator may be different than the code fo
r the constructor. Furthermore, sc still needs to be constructed and so the co
mpiler will insert a default constructor call anyway:
// Compiler re-writes AAA to this:
HasAClassMember::HasAClassMember() : sc() { sc = 99; } // BBB

which might result in being inefficient since it will run SomeClass::SomeClass
() and then SomeClass::operator=(). And of course, assignment is intended for
copying an already existing object, whereas construction is intended to initia
lize an object to some sane and initial state. Builtin types such as int do no
t have this particular concern, however, as a consistent style issue, it's wor
th treating them as such. Furthermore, through the life of the code, you may n
eed to change the type of the member (say from char * to std::string, and you
don't want a silent problem cropping up because of such a change.
Do note that the order of the member initializer lists in your code is not the
 order that the member will be initialized. Instead they are initialized in th
e order that the were declared in the class. For instance, given:

struct xyz {
    int i;
    int j; // j after i here
    xyz() : j(99), i(-99) { } // CCC
};
xyz X;

Note at runtime that X.j is not initialized before i. This is because j is def
ined after i. IOWs, think of it "as if" the compiler rewrites CCC as:
    xyz() : i(-99), j(99) { } // DDD

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How to get the dimension/bounds of an array?
Consider:
#define BOUNDS(array) sizeof(array) / sizeof(array[0])
// ...
char buf[99];
// ...size_t is from stddef.h in C, cstddef in C++
size_t bd = BOUNDS(buf);

In C++ you might do this:
#include <cstddef>
#include <iostream>

template <typename T, std::size_t N>
inline std::size_t bounds(T (&)[N]) { return N; }

int main()
{
     char a[99];
     int b[9999];
     char hello[] = "Hello";
     char *ptr = hello;

     std::cout << bounds(a) << std::endl; // outputs 99
     std::cout << bounds(b) << std::endl; // outputs 9999
     std::cout << bounds(hello) << std::endl; // outputs 6, includes null byte

     std::cout << bounds(ptr) << std::endl; // error
}

Note that ptr IS NOT an array, and so neither bounds nor BOUNDS will work corr
ectly with it (one could argue by design).
To pick up additional bounds, you might do:

template <typename T, std::size_t N, std::size_t N2>
inline std::size_t bounds2(T (&)[N][N2]) { return N2; }

Back to Top  Comeau C++ is packed with template support. Read about it! or eve
n Try it out!

------------------------------------------------------------------------------
--

Why can't I overload a function on return types?
As defined, C++ function overloading is determined by various rules placed upo
n a function's argument list. For instance:
void foo(int);
void foo(double);

However, this is not allowed:
int bar();
double bar(); // error: int bar() already exists

But why isn't it allowed? One may argue that the compiler should be able to fi
gure this out the same way (or kind of way) it figures out overloading based u
pon the argument types:
int i = bar(); // error, though intended to call 'int bar()'
double i = bar(); // error, though intended to call 'double bar()'

One obvious problem though is, which bar does this call:
// ...
int main()
{
    bar(); // call 'int bar()' or 'double bar()'???
}

Or, which do these call:
int i = 99 + bar();
double d = 99.99 + bar();
double d2 = 99 + bar();

And so on. So not only would allowing this be confusing in many cases, but as
it turns out, rules necessary to enforce/guide it would not be as similar as o
ne would originally think they would be to argument overloading.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Why can't I convert a char ** to a const char **?
The most common response/solution we've seen offered with respect to this issu
e is that the person with this problem should just use a cast. Unfortunately,
there is normally no additional explanation of the matter. So, that's not help
ful in understanding the matter. Worse, it can even be considered harmful advi
ce. The second most common response is a blunt "because", but that doesn't hel
p any either.
In fairness, this issue is pretty slippery, and in fact one really has to work
 to understand the example below (so get out a pen and paper). But this elusiv
eness is exactly why it can be harmful! Code can speak 1000 words, so here goe
s:

const char cc = 'x'; // cc is const, so you should NOT write to it
// cc = 'X'; // ErrorAAA: You should normally NOT write to a const

char *pc; // Some pointer to char
// pc = &cc; // ErrorBBB: attempt to assign const char * to char *

char **ppc = &pc; // Some pointer to a pointer to char, &pc is one of those

// This is the line in question that LOOKS legal and intuitive:
const char **ppcc = ppc; // ErrorCCC: const char ** = char ** not allowed
                         // But we're assuming it's allowed for now
                         // Could also have attempted:const char **ppcc = &pc;


*ppcc = &cc; // So, const char * = const char *, in particular: pc = &cc;
             // Note: But this was no good in line BBB above!
*pc = 'X'; // char = char, IOWs: cc = 'X'; ==> Yikes!

The issue at hand is that cc is const. But as you can see, if the conversion o
n CCC were allowed, it would be possible to inadvertently circumvent normal ty
pe checking. Moreover, it would do so silently. Because of this, a char ** can
not implicitly be assigned to a const char **, nor can it initialize one.
Do note that the pointers involved here are dealing with two levels of indirec
tion, not one. At first glance such a conversion seems like it should be allow
ed, because char * to const char * is allowed. But that's one level of indirec
tion and now you know that any such type hijacking attempt like the example ab
ove should be considered suspect. Now you know why the const matters here. Now
 you know why a cast may not be a safe suggestion. Conclusion: Intuition is no
t always right.

Often, instead of the cast, you want this:

const char * const *ppcc = ppc; // Notice the additional const

Note: Some earlier C++ compilers allow the conversion without the cast. As we
recall, the C++ committee fixed the wording on this before Standard C++ was ac
cepted and all current compilers should reject such a conversion, if implicit.
 We don't recall if Standard C requires rejecting this too, though as a qualit
y of implementation, you'd want to see a compiler at least give a warning abou
t it.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How many bits are in a byte?
Although it's common that the number of bits in a byte is 8, this is not so fo
r every system. That's right, a byte is not always 8 bits. A byte is one of th
ose terms which has an interesting history and ends up meaning different thing
s to different people. For instance, there are some computers where it is 6, 7
, 8, 9, 32-bits, and so on.
In C (or C++) you can tell what it is for your system by looking at limits.h (
known as climits in C++) where the macro CHAR_BIT is defined. It represents th
e "number of bits for the smallest object that is not a bit-field", in other w
ords, a byte. Note that it must be at least 8 (which mean that strictly speaki
ng, a CPU that supports a 6 bit byte has a problem with C or C++). Also note t
hat sizeof(char) is defined as 1 by C++ and C (ditto for the sizeof unsigned c
har, signed char, and their const and volatile permutations).

It might be helpful to show a quote from Standard C:

byte: "addressable unit of data storage large enough to hold any member of the
 basic character set of the execution environment. NOTE 1 It is possible to ex
press the address of each individual byte of an object uniquely. NOTE 2 A byte
 is composed of a contiguous sequence of bits, the number of which is implemen
tation-defined. The least significant bit is called the low-order bit; the mos
t significant bit is called the high-order bit."
character: "bit representation that fits in a byte"
Bt the way, note that C++ also supports numeric limits keyed by type. That is
to say, the <limits> headers provides some general attributes of types. You sh
ould review this is your C++ texts. In particular to note from the above is th
e digits attribute. For instance, std::numeric_limits<char>::digits might be 7
, whereas std::numeric_limits<unsigned char>::digits might be 8.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Is there a BOOL type?
How do I create an array of booleans?
There is no BOOL type in C++ or C, however, C++ supports a bool type (note the
 lowercase). All recent C++ compilers support it. Hand in hand with it is the
true and false boolean literals. These are keywords in C++, so no header file
is needed in order to use them. (C99, but not C90, supports a bool too, but in
 a different way, see below.) So you might have something like this:
int main()
{
    bool b = true;
    // ...
    if (b == false)...
}

Such a boolean might be used as a flag. As well, many conditions in C++ now ha
ve boolean "targets". That is, consider this:
int i = 99;
// ...
if (i == 99)...

Here, i is compared to 99 and if they are equal, the result of that expression
 if true, otherwise it is false. This means something like this is ok too:
b = i == 99;

How big is a bool? Its size is implementation-defined, so use sizeof to find o
ut for your platform. It is allowed take up as little space as a char.
There are various other details, especially about conversions to bool that you
 should be aware of. Therefore, you should check a recent C++ book for further
 details on bools. While you're at it, you'll probably want to check out std::
vector<bool> and the std::bitset template from the C++ Standard Library, espec
ially if an array of single bit booleans are necessary (the FAQ right after th
is one, #binaryliteral has an example using bitset). That said, a word of caut
ion is in order. As it turns out there are some requirements placed upon "cont
ainers" in the C++ Standard Library, and as std::vector<bool> is a partial spe
cialization of std::vector it turns out that it does not meet those requiremen
ts. In other words, std::vector<bool> is not a true container type. The C++ co
mmittee is currently weighing how to resolve this. Please take a look at http:
//www.comeaucomputing.com/iso/libr17.html#96 for an executive summary of their
 varied thoughts. For a discussion of the issues, look at the article on Herb
Sutter's site: http://www.gotw.ca/gotw/050.htm

C99 now also supports a boolean, however note that it will take some time befo
re many C compilers catch up with the new 1999 revision to C. Note that Comeau
 C++ 4.2.45.2 and above supports most C99 language features when in C99 mode.
Until most other C compilers support it, one must make do with various strateg
ies. An oft used one might be to do something like this:

#define FALSE 0
#define TRUE  1
typedef int BOOL;

Perhaps putting it into one of your header files. Here's another way:
typedef enum BOOL { FALSE, TRUE } BOOL;

By the way, it's situations like this is where BOOL comes from, either from fo
lks doing it on their own, or it's provided in some API they are using.
As to the specifics of C99's boolean, it has added a new keyword, _Bool (yes,
note the underscore, and the upper case letter) as a so-called extended intege
r type for booleans in C. As well, C99 support a new header, <stdbool.h>, whic
h does a few things. It defines the macro bool to expand to _Bool, true to exp
and to 1, false to expand to 0, and __bool_true_false_are_defined which expand
s to 1. The thinking here is that so many program already use the names bool a
nd Bool that a new independent name from the so-called reserved vendor namespa
ce was used. For programs where this is not the case (that is, where they do n
ot do something such as define their own bool -- presumably then this would be
 for new code), one would #include <stdbool.h> to get the "common names" forms
 just mentioned. This seems confusing, but so be it.

Anyway, you use __bool_true_false_are_defined so that you can control integrat
ing "old bools" with the new one. Until C compilers catch up with C99, perhaps
 it is best off using something like this:

#ifndef __bool_true_false_are_defined
  // <stdbool.h> not #include'd
  typedef enum _Bool { false, true } _Bool;
  typedef enum _Bool bool;
#endif

This would offer a reasonable transition model to the C99 bools.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

How do I print out a value in binary?
How do I code a binary literal?
In addition to decimal "notation", C and C++ can support octal and hex represe
ntations syntactically, both in constants, and when doing some I/O operations.
 This is so even though there is no octal or hex built in type. However, when
it comes to binary, there is no capability whatsoever, at least none supported
 directly by the respective standards.
Despite this, there are ways to obtain the same effect. For instance, consider
 the following C++ program, based upon the bitset template found in the C++ st
andard library:

#include <bitset>
#include <iostream>
#include <limits>
#include <climits>
#include <string>

int main()
{
    std::bitset<9> allOnes = ~0; // sets up 9 1's
    // bitset has an operator<<, so just output the "binary number":
    std::cout << allOnes << std::endl;

    int someInt = 1;

    // AA
    // Get the number of bits in an unsigned int
    const int bitsNeeded = std::numeric_limits<unsigned int>::digits;
    // Establish a bitset that's a copy of someInt
    std::bitset<bitsNeeded> intAsBits = someInt;
    // As with allOnes, just output the binary rep:
    std::cout << intAsBits << std::endl;

    // BB
    // This is provided as an alternate to AA because some compilers
    // do not yet support <limits>, which contains numeric_limits<>.
    // (See http://www.comeaucomputing.com/techtalk/#bitsinbyte )
    // If this is your situation, you'll need to use <climits>
    // (or perhaps even <limits.h> for your compiler) in order to obtain
    // CHAR_BIT.  The net effect is that bitsNeeded2 should yield the
    // same value as bitsNeeded, and of course intAsBits2 should output
    // the same characters as intAsBits did, though +1, since it does someInt+
+
    someInt++;
    const int bitsNeeded2 = sizeof(int) * CHAR_BIT;
    std::bitset<bitsNeeded2> intAsBits2 = someInt;
    std::cout << intAsBits2 << std::endl;

    // CC
    // This is just to show that if there is no reason to keep using
    // the bitset object later on in the code, then there may be no
    // reason to need intAsBits or intAsBits2.  So then this version
    // directly calls the bitset<> constructor with the int, hence
    // creating a temporary bitset which is then output in binary:
    someInt++;
    std::cout << std::bitset<bitsNeeded>(someInt) << std::endl;

    // DD
    // Just an example where a hex constant was assigned to the int
    // and another where it is called directly with a hex
    someInt = 0xf0f0;
    std::cout << std::bitset<bitsNeeded>(someInt) << std::endl;
    std::cout << std::bitset<bitsNeeded>(0xf0f0) << std::endl;

    // EE
    // The binary forms as above may sometimes be used for more manipulations.

    // Therefore, the "output" may not be to a stream but to a string.
    // In such cases, perhaps converting the bitset to a std::string is
    // what's wanted.
    //
    // Converting a bitset to a string is quite involved syntax-wise.
    // Take note in the following code that bitset has a to_string()
    // member function, however, it MUST BE CALLED:
    // * With the template keyword
    // * By explicitly specifying the template arguments to to_string()
    //   as to_string() takes no function arguments in order to deduce anythin
g.
    //
    // This is best put into an function instead of mainline code
    std::string s;
    // intAsBits declared above
    s = intAsBits.template to_string<char, std::char_traits<char>, std::alloca
tor<char> >();
    std::cout << s << std::endl;

    // FF
    // You can also fake-out actually writing a binary literal
    // by using a string.  Then, you can convert it to a long.
    std::string binaryFakeOut("0101010101010101");
    std::bitset<16> bfoAsBits(binaryFakeOut);
    unsigned long bfoAsLong = bfoAsBits.to_ulong();
    // As above, this can be done in one step:
    unsigned long x = std::bitset<16>(binaryFakeOut).to_ulong();
    // Or:
    unsigned long y = std::bitset<16>(std::string("0101010101010101")).to_ulon
g();

    return 0;
}

Note that this works for negative values as well as positive ones. There are m
any other things that bitset can do, however, the intent of this section is ju
st to show how you can convert some types into a binary representation. Check
out a good recent C++ book if you want to know more about bitset.
In some of the above, for instance EE, we suggested abstracting such a line aw
ay in a function, perhaps in a template function which is keyed off the type i
n order to compute the number of bits automatically, etc. Of course, once that
 has been done, dependencies on <limits>, etc., are no longer laced through th
e mainline code, just in the function you've written to handle this.

That said, this same organizational point would need to be considered even if
writing a C version:

#include <stdio.h>

void OutputIntAsBinary(unsigned int theInt)
{
    /* Find the "highest" bit of an int on your machine */
    unsigned int currentBit = ~0 - (~0U >> 1);
    while (currentBit) { /* Go through each bit */
        /* Is the respective bit in theInt set? */
        putchar(currentBit & theInt ? '1' : '0');
        currentBit >>= 1; /* Get next highest bit */
    }
    putchar('\n');
}

Of course, you'd probably not want to hard code putchar() in that case either,
 but pass a pointer to a function.
Back to Top  Check out Comeau C++ Online!

------------------------------------------------------------------------------
--

How can I execute another program from my program?
If you would like to execute an application from within your C or C++ program,
 then the respective standards support the system() function, which takes a C-
string argument. For instance:
#include <cstdlib> // use <stdlib.h> in C
#include <string>

int main()
{
    const char dateCommand[] = "date";
    std::string theDate;
    int result;

    result = std::system("date"); // run the date command and return
    result = std::system(dateCommand); // run it again

    theDate = "/usr/bin/";
    theDate += "date";
    result = std::system(theDate.c_str()); // yet again
}

Using system() attempts to run the command processor on your system, for insta
nce a shell. It returns the error code as determined by the command processor.
 This clearly depends upon whether or not there even is a command processor on
 your system. To see if there is a command processor being made available, pas
s the null pointer to system():
int result = system(0);
if (result)
    // there is a command processor
else
    // there is not a command processor

Similarly, the result from your execution attempt is returned:
result = system("date");

Its value, and the meaning of such a value, is implementation-defined. For man
y popular operating system, the PATH environment variable is expected to conta
in a list of paths where the command will be execute from. Of course too, you
can specify a full path name, as theDate does above. You can also pass argumen
ts to apps:
result = system("como file1.c file2.c");

These are just passed as you would normally type them on the command line to y
our command processor (on MS-OSs, the command processor might be command.com,
whereas on UNIX, it might be /bin/sh). Of course, be careful when specifying c
haracters that may end up being escape sequences (for instance, \c should be \
\c).
If you need some other sort of control over executing processes from your C or
 C++ programs, many operating systems support additional, though non-standard
routines. They often have names such as ?fork(), exec?(), spawn?(), etc., wher
e ? is some characters as documented in the extensions that the OS supports, a
s an example, execvp(), and so on.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's this "POD" thing in C++ I keep hearing about?
Posts in the C++ newsgroups often refer to something called PODs. However, mos
t books either don't mention them at all, or only mention them in passing. So
what exactly are they? And why are they mentioned so often on usenet? Why don'
t many books discuss them?
Well, for starters, POD is an acronym for "Plain Ol' Data". That's right, that
's an official technical term. :)

More generally, POD refers to POD-structs, POD-unions, and even to POD-scalars
. However, saying "POD" is usually meant to refer to POD-structs in most discu
ssions, so that's where I'll focus.

A POD-struct is an aggregate that may not contain non-static members which are
 references, user-defined destructor, user-defined assignment operators, point
ers to members, or members which are non-PODs (struct or union) or arrays of n
on-PODs (struct or union). Note that aggregate is not being used in the typica
l English meaning here, instead it has a specific C++ meaning. In particular,
an aggregate may not contain any user-defined constructors, base classes, virt
ual functions, or private/protected non-static data (so it may contain private
/protected static member data/functions). It's significant to point out that a
s a POD-struct is an aggregate, it may not contain those things either.

In other words, a POD wouldn't contain the things classes are usually used for
. What is it useful for then? In short, what this gives us is a shot at strong
 compatibility with C's structs. This is why they come up often. That is, comp
atibility with the C memory model is important to some programs.

This is not intended to be a full tutorial, but the above should address the i
nitial questions asked. As to why most books don't cover any of this, well, mo
st books are not worth buying. That said, what's important is not necessarily
to be able to recite and memorize the above, but to be able to use it and know
 what it means to do so (in other words, some books may discuss it, but not re
fer to it as PODs).

What's important is to obtain a fighting chance at multi-language programming,
 in specific to be able to obtain C compatibility. For that you need info on t
he memory layout, clear copying semantics, and no surprises. Note that althoug
h extern "C" does not depends upon PODs, often is it PODs which you will be pa
ssing and returning to extern "C" functions.

Coming full circle, what's going on here is that a POD struct in C++ is an int
ent to obtain what a normal struct would look like and be in C (which wouldn't
 be using inheritance or virtual functions or C++ features).

Some other quick POD facts:

The storage for a POD must be contiguous.
If X and Y are POD-structs, and their members are of the same number and order
 of layout compatible types, then X and Y are layout compatible. (This is as w
ith C).
If X and Y are POD-structs, and their initial members are of the same number a
nd order of layout compatible types, then if a union containing them contains
an object of either type X or Y, then it may use the respective member from ei
ther X or Y. (This is as with C).
A POD-struct may not have padding before its first member. (This is as with C.
)
A pointer to a POD-struct, say X, may be converted to a pointer to some type,
say T, if T is the first member of X. Said conversion should occur through a r
einterpret_cast. The opposite (converting a pointer to T to a pointer to X) is
 also allowed. (This is as with C.)
The offsetof macro from <cstddef> may only be used with POD-struct or POD-unio
n types. (This is as with C.)
It follows from above that a POD-class is a POD-struct (or a POD-union).
Yes, even built-in types such as int are POD types. This also includes normal
pointers and enum's. (Pointers to members are not PODs, as this is considered
a defect in the Standard.)
Arrays of POD types are still PODs.
const or volatile qualified PODs are still PODs.
PODs with constant initializers and static storage duration get initialized be
fore objects (POD or otherwise) requiring dynamic initialization.
If it wasn't clear from the above, a POD-struct can contain static members.
A POD-struct can contain typedefs, nested types, member functions, friends, an
d this-is-all-I-can-think-of-at-the-moment.
For more formal details about POD's, see the following sections in Standard C+
+ as starting points:

POD types: Section 3.9 paragraph 10
POD-structs and POD-unions: Section 9 paragraph 4
Aggregate: Section 8.5.1 paragraph 1
Copying back and forth with memcpy: Section 3.9 paragraph 2&3
Back to Top  Have you seen the Comeau Book Suggestions?

------------------------------------------------------------------------------
--

How can C++ functions call C functions?
How can C functions call C++ functions?
What's this extern "C" thing?
Most C++ compilers do something called name decoration, or name mangling. In s
hort, in order to support C++ function overloading, and C++ type-safe linkage,
 most C++ compilers will tack on some type encoding information onto the end o
f some of your identifiers. For instance, when Comeau C++ see this prototype

void foo(int, double);

it internally changes the name to foo__Fid, where the F indicates that it is a
 function, the i indicates the first argument is an int and the d indicates th
at the second argument is a double. Other compilers do this in a similar manne
r. Since the definition of this function will be similarly decorated, the link
er will resolve this symbol fine.
Now, consider something such as printf which is normally prototyped as follows
:

int printf(const char *, ...);

which hence might map into printf__FPCce. However, if printf was compiled with
 a C compiler, well, no C compiler that we know of does name decorating (altho
ugh they could, they don't), therefore, the name will not be resolved by the l
inker. To get around this, in most cases, you should use a linkage specificati
on. Here's the above example again:
extern "C" void foo(int, double);

Now most implementations will not decorate foo any longer. Of course, you woul
d extern "C" the function definition too (since the definition file should als
o be #includeing the header file which contains the prototype, that will be sa
tisfactory as far as the compiler is concerned, though you should consider sel
f-documenting code). As well, if you have many such functions, you can create
linkage blocks, consider:
// stdio.h
extern "C" {
    // ...
    int printf(const char *, ...);
    // ...
}

Here, most C++ compilers will not decorate printfs name, therefore, it will pr
obably now link with the binary version that was compiled by the C compiler. I
t's often useful to create a "co-ed" header file, so in such cases, this codin
g technique might be helpful:
// stdio.h
#ifdef __cplusplus
extern "C" {
#endif

// stuff from before

#ifdef __cplusplus
}
#endif

Since Standard C is not required to define __cplusplus, then, when compiling w
ith a C compiler, the extern block won't be established (but of course all the
 prototypes and such will be, which is as the C compiler would expect it).
Please note that name decoration is not required by C++, it is strictly an imp
lementation detail. However, all C++ compilers do it. Similarly, a linkage spe
cification should be considered a fighting chance at cross language linkage an
d not a guarantee. Again though, for most platforms, the reality is that it wi
ll work fine.

Too, do note that a linkage specification does not bring you into the other la
nguage. That is, you are still writing C++ code. As such, also note that doing
 something like passing a class based object, a reference, etc., to a C functi
on means you are on your own. Note that other things effect name decoration to
o, such as a class name, namespace, etc. As well, you won't be overloading a f
unction which you've extern "C"d because then you would have two functions wit
h the same name (since most implementation wouldn't mangle them).

The above has so far considered only the scenario of calling a C function from
 C++. The contrary, calling a C++ function from a C function, has the same sol
ution. In other words, if you extern "C" a C++ function, then most implementat
ions won't mangle it, therefore, most C compilers will be able to link with it
. As just mentioned, it the C++ function expects something such as a reference
 argument, you are of course on your own. Of course as well, a C++ application
 can use C++ functions which have been extern "C"d.

There are other aspect to linkage specifications that you might want to be awa
re of. For instance, it can be applied to objects. With the above under your b
elt, you may now want to pursue a quality C++ text book on this matter.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Why is there a const after some function names?
void SomeClass::MemberFunc() const { /*WHY THE CONST?*/ }
What is the mutable keyword?
Given the following snippet:
class xyz {
    int x;
    int y;
    mutable int z;
    // ...
public:
    void foo() { x = 99; }
    int getx() { return x; }
    int gety() const { return y; }
    void bar() const { z = -99; }
};

We know that in effect, the member functions really are:
class xyz { // ...
    void foo() { this->xyz::x = 99; }
    int getx() { return this->xyz::x; }
    int gety() const { return this->xyz::y; }
    void bar() const { this->xyz::z = -99; }
}

Note that gety() has a const after its argument list (which is void in this ex
ample), whereas foo() and getx() do not. Because of the const, gety() is calle
d a const member function. This means that the type of its this pointer is a c
onst xyz * const. In the case of foo() and getx(), which are then non-const me
mber functions, the type of their this pointer is a xyz * const. In other word
s, an implication is that gety() cannot modify the object it was called with,
whereas the other two can. As such, note that foo() modifies x, however, note
that getx() and gety() just return copies of some of xyzs members. This seems
to imply that getx should also have been declared as a const member function.

Because of the difference in the qualification of what the this pointer points
 to, consider the following:

xyz A;
// ...
A.foo(); // ok
int ax = A.getx(); // ok
int ay = A.gety(); // ok

const xyz B;
B.foo(); // Not ok, expect a diagnostic
int bx = B.getx(); // Not ok, expect a diagnostic
int by = B.gety(); // ok

We observe here that a non-const object can be used with all the functions. We
 also observe that the const object's integrity will be upheld if non-const me
mber functions are called upon it, because they are allowed to modify the obje
ct, but if the object is const, that would not be a good thing.
Another point worth noting is member z. In particular, it is declared mutable.
 This means that even if a object is declared const (meaning it is immutable,
that is, not modifiable), any member declared mutable are well mutable, that i
s, modifiable. This is upheld through const member functions, therefore, membe
r bar() is able to modify z even though it was declared as a const member func
tion.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's the difference between C++ and VC++?
What's the difference between C++ and Borland C++?
Standard C++ is the ISO international standard for C++. That is, C++ is a lang
uage (and library) specification detailing many aspects, requirements, rules,
etc. about itself. It is not controlled by any one vendor, as it is a neutral
international standard. So there is only one language, Standard C++.
Do note that just because a product name uses C++ in it, does not mean that it
 is compliant with the C++ standard. There are various vendors who have implem
entations that target Standard C++. For instance, Comeau C++, or Microsoft's V
isual C++ (aka VC++). Implementations are available for specific platforms. Th
e implementations are compliant to the Standard in varying degrees, also, the
implementations may or may not have extensions, which would be documented by t
he vendor of such a product.

Usually you want to compare implementations with each other. That is, you woul
dn't necessarily ask what the advantage of C++ is over VC++, because that tend
s to be a non-question. That is, usually you don't want to look at a specific
implementation of C++ as a language in and of itself. This doesn't mean that y
ou cannot discuss the products, or ask what their extensions, platforms, easy
of use, speed, etc., are, so long as you are aware that they are specifics abo
ut what a particular vendor does.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What's an INTERNAL COMPILER ERROR?
If it's not obvious to you, compilers are software. Sometimes they will run in
to problems and crash, just like any other application. Other times, they will
 detect a problem and give up. In such cases, you will get some sort of diagno
stic, probably saying that the compiler has detected an internal compiler erro
r.
Usually you should contact your vendor about such an error. Too though, the di
agnostic may give you information about the line of code which caused the erro
r, and you may or may not be able to figure out a work around from there.

Here's some situations which may be the indirect cause of the internal error:


Run out of disk space, or something wrong with the drive.
Run out of swap space
Run out of RAM
Some bad RAM chips (perhaps in upper memory)
Your system may be out of other resources, like file handles.
There may be some misbehaving application.
with some of these being dependent upon your operating system, etc.
Here's some additional points to consider:

Reboot your computer and see if the problem persists.
If you have an older compiler, the vendor may have solved the problem and an u
pgrade may be in order.
Sometimes an internal compiler limit (ugh!) you may be overflowing, and in tho
se cases it may help to split more complicated expressions into multiple state
ments. Or, you may need to split a very large source file into multiple files.

No matter what, if you are able to find out the line of code which is producin
g the error, then try to create a smaller version of the source, as that might
 reveal some information to you about the nature of the problem.
It never hurts to have more than one compiler so that you can try the code wit
h another vendor, or under another operating system, and see if that is benefi
cial in revealing what the problem may be.
Again though, this problem is normally rooted in a compiler bug, so the above
is mainly being mentioned as something to get you out of a bottleneck situatio
n where you cannot compile anything, and so that you have something to report
to your vendor.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What is the template typename keyword used for?
What's the difference between typename and typedef
For starters, typename can be used instead of class when declaring template pa
rameters, for instance this:
template <class T> class xyz { };

could have been written as:
template <typename T> class xyz { };

These two definitions of xyz are considered equivalent since template paramete
rs using class or typename are interchangeable.
Additionally, there are various contexts where the compiler needs to know whet
her it is dealing with a declaration or an expression. In the case of template
s, a similar parsing issues comes up. In particular, if T is a template parame
ter as it is in xyz above, then what does it mean for it to use say T::x? In o
ther words, if the compiler does not know what T is until you instantiate it,
how could it know what x is, since it is based upon T? Consider:

template <typename T> class xyz {
    void foo() { T::x * p; /* ... */ p = blah; }
};

Does this declare p or does it multiply some p somewhere by T::x? If it should
 be a declaration, then you would do this to make that clear:
template <typename T> class xyz {
    void foo() { typename T::x * p; /* ... */ p = blah; }
};

Now we know that blah is being assigned to the local p in foo.
Note that there is no guarantee that when you actually instantiate the templat
e that x is actually a type. If it's not, you'll get an error at that point. A
nyway, make sure that typenamed things will actually eventually refer to types
.

Note too that some earlier compilers do not support the typename keyword at al
l. As well, some current compiler which do support it may have a switch to dis
able it, so double check your situation if your compiler won't accept your usi
ng this keyword. Furthermore, some compilers and/or modes will make an attempt
 to guess which names are actually supposed typenames. It can clearly do this
in some cases, and in some cases it is not required because the compiler requi
res a type, but to expect it to do it in all cases is not possible.

Also worth pointing out is that typename is not the same as typedef. In brief,
 typedef creates an alias (another name) for an existing type, whereas typenam
e acts as a contextual disambiguator as described above. In fact, you will oft
en see them used together, for instance:

template <typename T> class xyz {
    typedef typename T::SomeTypeInT SomeNewTypeForxyz;
};

By the way, if you are using just a T, then it does not require typename, so t
his is wrong:
template <typename T> class abc {
    typedef typename T abcT;
};

For instance, here is the error message from Comeau C++ about this:
Comeau C/C++ 4.2.43 (Mar  3 2000 18:18:13) for Solaris_SPARC_2_x
Copyright 1988-2000 Comeau Computing.  All rights reserved.
MODE:strict errors C++

"tn.c", line 2: error: a class or namespace qualified name is required
      typedef typename T abcT;
                       ^

There are other examples where typename can be used and their premise is simil
ar to the above.

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

What does the ++ in C++ stand for?
How do you pronounce C++?
C++ is pronounced "C" "plus" "plus".
C++ was originally called "C With Classes". The problem was that people starte
d called C With Classes things like "new C" and even just plain old C. Because
 of this, AT&T management suggest that Stroustrup change its name to be more p
olitically courteous. So, it (shortly) came to be known as C84. However, then
the problem was that people began calling original C names like "old C". Furth
ermore, ANSI C was being developed around that time too, and C84 would clash w
ith it too, because during standardization, languages usually get coined names
 like LANGUAGEYY, so ANSI C might end up being something like C86, so naming C
++ as C84 would just make that confusing, especially if a new version of C84 c
ame along!

So a new name still needed to be found. Around 1983 Rick Mascitti suggested C+
+. It's a pun off of the ++ operator in C, which deals with incrementing somet
hing (although it is semantically problematic since it should really be ++C),
but anyway: first C, then C++, get it?

Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Do you have a question to add?
Do not hesitate to email us at support@comeaucomputing.com if you have any oth
er questions or concerns you would like to see covered.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Comeau Computing.
--

Do you have a question to add?
Do not hesitate to email us at support@comeaucomputing.com if you have any oth
er questions or concerns you would like to see covered.
Back to Top  Back to Comeau Home

------------------------------------------------------------------------------
--

Comeau Computing.
Copyright &copy; Comeau Computing. All rights reserved.
Revised: April 2, 2003.


--
                      *
          *                                  *
                          *             *
                      no more to say
                  ★     just wish you   ★
                            good luck

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.50]


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

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