k
is an int
that's been assigned the value 4,
(k - 2)*7 // type: int, value: 14
is an expression of type int
and value 14.
k = 5 // type: int, value: 5
Here, k
is once again a variable of type int
.
The type of this expression is int
, and the value is 5.
In general, an assignment expression has the same type as the
object being assigned to, and the same value as that object after the
assignment is carried out. Thus, oddly enough, if x
is a
variable of type double
, then
(x = 3.4)*2.0 // type: double, value: 6.8, there is a side effect
makes perfect sense. In particular,
double
, and after it is evaluated, it has value 6.8.
x
to 3.4.
cout << x // type: ostream, value: cout, there is a side effect
As we saw last lecture, cout
is an object of type
ostream
.
cout << x
also
has type ostream
, and its value is just cout
(like multiplying zero by anything, you still get zero).
x
gets written out to the screen!
int k;
cin >> k;
cout << k+7;
What is the value of the expression k+7
?
Well, it depends what the user enters for input. That's
something that cannot be known until the program is run.
k+1
is something we
do know before running the program: it's int
. Most of the time
(especially for the subset of C++ we concentrate on) the type of an
expression is known at compile time, i.e. when compiling the program,
as opposed to running it. Because of this, C++ is said to be a "statically
typed" language.
k = 4
is an expression as used
in (k=4)*3
will evaluate to 12, the statement k =
4;
as a line of code ending in a semicolon is not an expression.
int k
for example, are not expressions - regardless of whether the
; is there.
double x = 3.3;
int k = -2;
// x*k : type and value?
What is the type and value of the expression x*k
? // x*k -- type: double, value: -6.6
Explanation: C++ knows how multiply two int
objects, and it knows how to
multiply two double
objects, but it doesn't know how to multiply
one of each. However, it understands that an int
can be
converted to a double
and vice versa. So it converts one
and performs the multiplication on two objects of the same type. But which way
should it go?
Specifically, the direction is as follows:
→ int → double
int
is converted (or promoted)
to a double, and the operation is performed on two doubles. It wouldn't
make nearly as much sense the other way round, would it?
Some more examples on the right:
So, for example, consider the following code:
double x = 3.3;
int k;
cout << (k = x) << endl;; // expression k=x -- type: int, value: 3
In the above, the expression k=x
is of type int
with value 3. C++ truncates double
s when converting to
int
s.
k
is an int
and you'd like to
convert it to the equivalent double
, you'd write:
(double)kwhich would "cast"
k
to type
double
. C++ actually adds functionality to C, i.e. it is
literally C plus some other stuff. So C constructs like
(double)k
all work.
m
and n
are int
s,
n
being the larger. We'd like to print out the value of
m/n
. Well,
cout << m/n << endl;
double
s. To explicitly convert them to double
s
first we'd write:
cout << double(m)/double(n) << endl;
Quick check: Can you explain what type and value you get with the following code?
1 / double(2)
Answer (drag your mouse): It's of type double and
value 0.5. Integer 1 is implicitly promoted to the double type before the
division operation.
Explicit conversion can get tricky later on, but at this stage it's as simple as writing the new type name followed by the old object in ()'s.
Some Quick Conversion Rules |
int → double : This does exactly what you'd expect. |
double → int : This simply truncates the value, meaning that whatever's after the decimal point just gets chopped. You can get in trouble if the double value is too big. |
bool → int : true goes to 1, false goes to 0. |
int → bool : 0 goes to false, everything else goes to true; |
int → char : if the int is in the range 0-127 the char value is determined by the ASCII table; |
char → int : the int value is determined by the ASCII table; |
char
s, int
s, bool
s, and
double
s - be represented by zeros and ones? Our
understanding of types will really depend on being able to answer these
questions.
The memory of a computer is simply one long sequence of bits.
However, these bits are organized into chunks of 8 called
bytes. To emphasize, a byte consists of 8-bits. In a
byte, we can represent the numbers from 0 to 255.
We strongly recommend that you review the class on Digital Data from the SY110 website. Here's a link to a full ASCII table.
bool
sbool
is just a way of interpreting a byte of
memory. If all 8 bits of the byte are zero, the interpretation as a bool
is false
. Otherwise, the interpretation of a bool is
true
.
char
schar
is just a different way of interpreting a byte
of memory! For example, the byte 01100001 is interpreted as the character
a
. This interpretation of bytes as characters is called the
ASCII encoding, and this table,
for example, shows you the whole thing. Interpreting 01100001 as a number
in binary, we get the number 97, and if you look up 97 in the table,
you'll see that it corresponds to the character a
.
Already we see one of the fundamental ideas behind computing, different
types of objects may be represented by treating sequences of 0's and 1's
in different ways. That's why C++ needs to keep track of the types of
objects, so it knows how to interpret the contents of the chunk of memory
associated with each object.
In fact, you can look at a char
as just being a small integer
(I say small because 8-bits only allows us the range [0,255]). This
interpretation pretty much tells us what to expect of conversions between
char
s and int
s.
Arithmetics on char
s.
One interesting feature of this match-up between characters and numbers is
that statements like
cout << ('b' - 'a') << endl
make perfect sense.
'b'
corresponds to the number 98, and 'a'
to
the number 97.
int
subtraction
problem 98 - 97, which evaluates to 1.
cout << ('b'+3) << ' ' << char('b' + 3) << endl;
will output
101 e
int
s00000000 00000000 00000000 00000101... or it could be represented as
00000101 00000000 00000000 00000000... depending on what's referred to as as the "endianness" of the underlying machine. That particular distinction is beyond the scope of this course, but you will encounter it in subsequent CS/IT course.
int
on your PC consists of 4 bytes, or 32 bits, so it
can represent very large numbers. We're not going to get into the
question of how negative numbers are represented in binary. Essentially
an int
looks like the binary number representation we just
talked about, but in 32 bits.
So, the int
5 is represented in the computer as:
00000000 00000000 00000000 00000101
double
sdouble
takes up 8 bytes, or 64 bits. The format is more
complex, however, and we will not go over it here, except to say that it
is a binary version of the familiar scientific notation. However, instead
of a base of 10, it uses a base of two. (Example: 12 is represented as 1.5
x 2^3.) Let it suffice to say that the double
1.0 is
represented by the following 64 bits:
00000011 11111111 11111111 00000000 00000000 00000000 00000000 00000000
cout << 3.1 + int( bool( int(3.1) ) );
Answer: 4.1
char, bool, int,
double
? Answer: 8, 8, 32, 64