It's a randomly ordered collection containing a few questions newbies might ask.
Hopefully someday I'll be able to improve this section, but for now, it is
incomplete and unorganized. If that bothers you, my suggestion is to click
that little x on the extreme upper right of your browser window
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Read the FAQ, especially the section on learning C++, read comp.lang.c++, read books plural.
But if everything still seems too hard, if you're feeling bombarded with mysterious terms and concepts, if you're wondering how you'll ever grasp anything, do this:
That's it. Just practice and play. Hopefully that will give you a foothold.
Here are some places you can get "sample problems" (in alphabetical order):
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Some compilers accept
As to the specific return value, if you don't know what else to return just
say
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
C programmers often use
If you're writing C++ code, you should use
This C++ code shows the best way to declare a function that takes no parameters:
This C++ code both declares and defines a function that takes no parameters:
The following C++ code also declares a function that takes no parameters, but
it uses the less desirable (some would say "abomination") style,
Actually this
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Other related questions: If a
Answer: It's usually a good idea to write code that can be ported to a different operating system and/or compiler. After all, if you're successful at what you do, someone else might want to use it somewhere else. This can be a little tricky with built-in types like int and short, since C++ doesn't give guaranteed sizes. However C++ gives you two things that might help: guaranteed minimum sizes, and that will usually be all you need to know, and a standard C header that provides typedefs for sized integers.
C++ guarantees a char is exactly one byte
which is at least 8 bits, short is at least 16 bits, int is at
least 16 bits, and long is at least 32 bits. It also guarantees the
unsigned version of each of these is the same size as the original,
for example,
When writing portable code, you shouldn't make additional assumptions about
these sizes. For example, don't assume int has 32 bits. If you have
an integral variable that needs at least 32 bits, use a long or
The other option is to use the following standard C header (which may or may not be provided by your C++ compiler vendor):
That header defines typedefs for things like int32_t and uint16_t, which are a signed 32-bit integer and an unsigned 16-bit integer, respectively. There are other goodies in there, as well. My recommendation is that you use these "sized" integral types only where they are actually needed. Some people worship consistency, and they are sorely tempted to use these sized integers everywhere simply because they were needed somewhere. Consistency is good, but it is not the greatest good, and using these typedefs everywhere can cause some headaches and even possible performance issues. Better to use common sense, which often leads you to use the normal keywords, e.g., int, unsigned, etc. where you can, and use of the explicitly sized integer types, e.g., int32_t, etc. where you must.
Note that there are some subtle tradeoffs here. In some cases, your computer might be able to manipulate smaller things faster than bigger things, but in other cases it is exactly the opposite: int arithmetic might be faster than short arithmetic on some implementations. Another tradeoff is data-space against code-space: int arithmetic might generate less binary code than short arithmetic on some implementations. Don't make simplistic assumptions. Just because a particular variable can be declared as short doesn't necessarily mean it should, even if you're trying to save space.
Note that the C standard doesn't guarantee that
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
If it bothers you, call it a "const identifier" instead.
The main issue is to figure out what it is; we can figure out what to call it later. For example, consider the symbol max in the following function:
It doesn't matter whether you call max a const variable or a const identifier. What matters is that you realize it is like a normal variable in some ways (e.g., you can take its address or pass it by const-reference), but it is unlike a normal variable in that you can't change its value.
Here is another even more common example:
In this example, you would need to add the line
It is generally considered good programming practice to give each "magic number" (like 107) a symbolic name and use that name rather than the raw magic number.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
const identifiers are often better than
In short, const identifiers act like they're part of the language because
they are part of the language. The preprocessor can be thought of as
a language layered on top of C++. You can imagine that the preprocessor runs
as a separate pass through your code, which would mean your original source
code would be seen only by the preprocessor, not by the C++ compiler itself.
In other words, you can imagine the preprocessor sees your original source
code and replaces all
There are cases where
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Yes, that's exactly what I'm saying: the preprocessor is evil.
Every
Sometimes we need the preprocessor, such
as the
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Most (not all) implementations have a "standard include" directory, sometimes directories plural. If your implementation is like that, the headers in the standard library are probably a subset of the files in those directories. For example, iostream and string are part of the standard library, as is cstring and cstdio. There are a bunch of .h files that are also part of the standard libarary, but not every .h file in those directories is part of the standard library. For example, stdio.h is but windows.h is not.
You include headers from the standard library like this:
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
The short answer is: Just like the rest of your team. In other words, the team should use a consistent approach to whitespace, but otherwise please don't waste a lot of time worrying about it.
Here are a few details:
There is no universally accepted coding standard when it comes to whitespace. There are a few popular whitespace standards, such as the "one true brace" style, but there is a lot of contention over certain aspects of any given coding standard.
Most whitespace standards agree on a few points, such as putting a space
around infix operators like
...and others...
IMPORTANT: Do NOT email me with reasons your whitespace approach is better than the others. I don't care. Plus I won't believe you. There is no objective standard of "better" when it comes to whitespace so your opinion is just that: your opinion. If you write me an email in spite of this paragraph, I will consider you to be a hopeless geek who focuses on nits. Don't waste your time worrying about whitespace: as long as your team uses a consistent whitespace style, get on with your life and worry about more important things.
For example, things you should be worried about include design issues
like when ABCs should be used, whether inheritance should
be an implementation or specification technique, what testing and inspection
strategies should be used, whether interfaces should uniformly have a
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Probably not.
In many (not all) cases, it's best to name your numbers so each number appears only once in your code. That way, when the number changes there will only be one place in the code that has to change.
For example, suppose your program is working with shipping crates. The weight
of an empty crate is 5.7. The expression
Now that's the general rule of thumb. But unfortunately there is some fine print.
Some people believe one should never have numeric literals scattered in the code. They believe all numeric values should be named in a manner similar to that described above. That rule, however noble in intent, just doesn't work very well in practice. It is too tedious for people to follow, and ultimately it costs companies more than it saves them. Remember: the goal of all programming rules is to reduce time, cost and risk. If a rule actually makes things worse, it is a bad rule, period.
A more practical rule is to focus on those values that are likely to change.
For example, if a numeric literal is likely to change, it should appear only
once in the software, usually as the initializer of a const identifier.
This rule lets unchanging values, such as some occurrences of 0, 1, -1, etc.,
get coded directly in the software so programmers don't have to search for the
one true definition of one or zero. In other words, if a
programmer wants to loop over the indices of a vector, he can simply
write
Obviously people might argue over exactly which values are "likely to change," but that kind of judgment is why you get paid the big bucks: do your job and make a decision. Some people are so afraid of making a wrong decision that they'll adopt a one-size-fits-all rule such as "give a name to every number." But if you adopt rules like that, you're guaranteed to have made the wrong decision: those rules cost your company more than they save. They are bad rules.
The choice is simple: use a flexible rule even though you might make a wrong decision, or use a one-size-fits-all rule and be guaranteed to make a wrong decision.
There is one more piece of fine print: where the const identifier should be defined. There are three typical cases:
As a last resort, make it static within a namespace or perhaps put it
in the unnamed namespace. Try very hard to avoid using
(As used throughout the FAQ, "evil" doesn't mean "never use it." There are times when you will use something that is "evil" since it will be, in those particular cases, the lesser of two evils.)
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
You should use these suffixes when you need to force the compiler to treat the
numeric literal as if it were the specified type. For example, if x is
of type float, the expression
The U suffix is similar. It's probably a good idea to use unsigned
integers for variables that are always >= 0. For example, if a variable
represents an index into an array, that variable would typically be declared
as an unsigned. The main reason for this is it requires less code, at least
if you are careful to check your ranges. For example, to check if a variable
is both >= 0 and < max requires two tests if everything is signed:
If you end up using unsigned variables, it is generally a good idea to force
your numeric literals to also be unsigned. That makes it easier to see that
the compiler will generate "unsigned arithmetic" instructions. For example:
The L suffix is not as common, but it is occasionally used for similar reasons as above: to make it obvious that the compiler is using long arithmetic.
The bottom line is this: it is a good discipline for programmers to force all
numeric operands to be of the right type, as opposed to relying on the C++
rules for promoting/demoting numeric expressions. For example, if x
is of type int and y is of type unsigned, it is a good idea to
change
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Some people are confused about the
Answer: The
Along with a similar group formed using the
Note: boolean algebra can be used to transform each of the
The point of all this is simple: the
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
No!
Despite what your grade school math teacher taught you, these equivalences don't always work in software, especially with floating point expressions or user-defined types.
Example: if a is a floating point NaN, then both
Example: if a is an object of class Foo that has overloaded
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
NaN means "not a number," and is used for floating point operations.
There are lots of floating point operations that don't make sense, such as dividing by zero, taking the log of zero or a negative number, taking the square root of a negative number, etc. Depending on your compiler, some of these operations may produce special floating point values such as infinity (with distinct values for positive vs. negative infinity) and the not a number value, NaN.
If your compiler produces a NaN, it has the unusual property that it is not
equal to any value, including itself. For example, if a is NaN, then
Here's how to check if a value is NaN:
Note: although
In any case, DO NOT WRITE ME just to say that your compiler does/does
not support
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
(On one C++ implementation, this prints 0.429993)
Disclaimer: Frustration with rounding/truncation/approximation isn't really a C++ issue; it's a computer science issue. However, people keep asking about it on comp.lang.c++, so what follows is a nominal answer.
Answer: Floating point is an approximation. The IEEE standard for 32 bit float supports 1 bit of sign, 8 bits of exponent, and 23 bits of mantissa. Since a normalized binary-point mantissa always has the form 1.xxxxx... the leading 1 is dropped and you get effectively 24 bits of mantissa. The number 1000.43 (and many, many others, including some really common ones like 0.1) is not exactly representable in float or double format. 1000.43 is actually represented as the following bitpattern (the "s" shows the position of the sign bit, the "e"s show the positions of the exponent bits, and the "m"s show the positions of the mantissa bits):
The shifted mantissa is 1111101000.01101110000101 or 1000 + 7045/16384. The fractional part is 0.429992675781. With 24 bits of mantissa you only get about 1 part in 16M of precision for float. The double type provides more precision (53 bits of mantissa).
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Because floating point arithmetic is different from real number arithmetic.
Bottom line: Never use
Here's a simple example:
The above "surprise" message will appear on some (but not all) compilers/machines. But even if your particular compiler/machine doesn't cause the above "surprise" message (and if you write me telling me whether it does, you'll show you've missed the whole point of this FAQ), floating point will surprise you at some point. So read this FAQ and you'll know what to do.
The reason floating point will surprise you is that float and double values are normally represented using a finite precision binary format. In other words, floating point numbers are not real numbers. For example, in your machine's floating point format it might be impossible to exactly represent the number 0.1. By way of analogy, it's impossible to exactly represent the number one third in decimal format (unless you use an infinite number of digits).
To dig a little deeper, let's examine what the decimal number 0.625 means. This number has a 6 in the "tenths" place, a 2 in the "hundreths" place, and a 5 in the "thousanths" place. In other words, we have a digit for each power of 10. But in binary, we might, depending on the details of your machine's floating point format, have a bit for each power of 2. So the fractional part might have a "halves" place, a "quarters" place, an "eighths" place, "sixteenths" place, etc., and each of these places has a bit.
Let's pretend your machine represents the fractional part of floating point numbers using the above scheme (it's normally more complicated than that, but if you already know exactly how floating point numbers are stored, chances are you don't need this FAQ to begin with, so look at this as a good starting point). On that pretend machine, the bits of the fractional part of 0.625 would be 101: 1 in the ½-place, 0 in the ¼-place, and 1 in the ⅛-place. In other words, 0.625 is ½ + ⅛.
But on this pretend machine, 0.1 cannot be represented exactly since it cannot be formed as a sum of a finite number of powers of 2. You can get close but you can't represent it exactly. In particular you'd have a 0 in the ½-place, a 0 in the ¼-place, a 0 in the ⅛-place, and finally a 1 in the "sixteenths" place, leaving a remainder of 1/10 - 1/16 = 3/80. Figuring out the other bits is left as an exercise (hint: look for a repeating bit-pattern, analogous to trying to represent 1/3 or 1/7 in decimal format).
The message is that some floating point numbers cannot always be represented exactly, so comparisons don't always do what you'd like them to do. In other words, if the computer actually multiplies 10.0 by 1.0/10.0, it might not exactly get 1.0 back.
That's the problem. Now here's the solution: be very careful when comparing floating point numbers for equality (or when doing other things with floating point numbers; e.g., finding the average of two floating point numbers seems simple but to do it right requires an if/else with at least three cases).
Here's the wrong way to do it:
If what you really want is to make sure they're "very close" to each other
(e.g., if variable a contains the value
There are many ways to define the
Note: the above solution is not completely symmetric, meaning it is possible
for
For other useful functions, check out the following (listed alphabetically):
Double-check your assumptions, including "obvious" things like how to compute averages, how to solve quadratic equations, etc., etc. Do not assume the formulas you learned in High School will work with floating point numbers!
For insights on the underlying ideas and issues of floating point computation, start with David Goldberg's paper, What Every Computer-Scientist Should Know About Floating Point Arithmetic or here in PDF format. You might also want to read this supplement by Doug Priest. The combined paper + supplement is also available. You might also want to go here for links to other floating-point topics.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
I know it's hard to accept, but floating point arithmetic simply does not work like most people expect. Worse, some of the differences are dependent on the details of your particular computer's floating point hardware and/or the optimization settings you use on your particular compiler. You might not like that, but it's the way it is. The only way to "get it" is to set aside your assumptions about how things ought to behave and accept things as they actually do behave.
Let's work a simple example. Turns out that on some installations,
On many (not all) computers, you will end up in the if block even when
{bold{Why}bold}, you ask, can that happen? Good question; thanks for asking.
Here's the answer (with emphasis on the word "often"; the behavior depends on
your hardware, compiler, etc.): floating point calculations and comparisons
are often performed by special hardware that often contain special registers,
and those registers often have more bits than a double. That means
that intermediate floating point computations often have more bits than
Said another way, intermediate calculations are often more precise (have more
bits) than when those same values get stored into RAM. Think of it this way:
storing a floating point result into RAM requires some bits to get discarded,
so comparing a (truncated) value in RAM with an (untruncated) value within a
floating-point register might not do what you expect. Suppose your code
computes
Did you catch that? Your particular installation might store the result of
one of the
{bold{It gets worse}bold}; better sit down. Turns out that the behavior can
depend on how many instructions are between the
Your mouth should be hanging open by now. If not, you either learned pretty
quickly from the above or you are still asleep. Read it again. When
{bold{Reason:}bold} if the compiler can prove that you're not messing with any
floating point registers in the
If you didn't hear anything else in this whole discussion, just remember this: floating point comparisons are tricky and subtle and fraught with danger. Be careful. The way floating point actually works is different from the way most programmers tend to think it ought to work. If you intend to use floating point, you need to learn how it actually works.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
An enumeration such as
When you create an object of an enumeration type, e.g.,
An expression of an enumeration type can be converted to a temporary
int. An analogy may help here. An expression of type float can be
converted to a temporary double, but that doesn't mean float is a subtype
of double. For example, after the declaration
The above conversion is very different from a subtype relationship, such as
the relationship between derived class Car and its base class Vehicle.
For example, an object of class Car, such as
Final note, especially for C programmers: the C++
compiler will not automatically convert an int expression to a
temporary Color. Since that sort of conversion is unsafe, it
requires a cast, e.g.,
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Let's consider this enumeration type:
The best way to look at this (C programmers: hang on to your seats!!) is that the values of this type are red, white, and blue, as opposed to merely thinking of those names as constant int values. The C++ compiler provides an automatic conversion from Color to int, and the converted values will be, in this case, 0, 1, and 2 respectively. But you shouldn't think of blue as a fancy name for 2. blue is of type Color and there is an automatic conversion from blue to 2, but the inverse conversion, from int to Color, is not provided automatically by the C++ compiler.
Here is an example that illustrates the conversion from Color to int:
The following example also demonstrates the conversion from Color to int:
However the inverse conversion, from int to Color, is not automatically provided by the C++ compiler:
The last line above shows that enumeration types are not ints in disguise. You can think of them as int types if you want to, but if you do, you must remember that the C++ compiler will not implicitly convert an int to a Color. If you really want that, you can use a cast:
There are other ways that enumeration types are unlike int. For example,
enumeration types don't have a
Caveat on the last line: it is legal to provide an overloaded operator that
would make that line legal, such as definining
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
An excellent place to start is The Correct C++ Tutorial. It's goal is to give you correct advice, not to make it easy for you. It's not quick, it's not simple, it's not easy, it's just correct. If you're smart, that's the tradeoff you'll want.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Mar 1, 2006