Compiler Responsibilities
I know you said that only the value of a variable gets stored in memory, but when we say say
std::cout << myVar;
, how does it know whether the memory formyVar
holds anint
, adouble
or something else entirely?Actually, in Python it doesn't know until the program is running!
But in C++, we know beforehand, because we declared the variable with its type, like
double myVar = 3.0;
.That knowledge about the
myVar
variable is embedded into the instructions that form the object code for the progam (e.g., some instructions that say “write the double value 3.0 into stack slot S3”).And those machine instructions are determined by the compiler?
Yes. In fact, the compiler's responsibilities are our next topic.
The Compiler Handles Types
Since memory for variables only stores their values, not their types, errors related to the type of variables have to come from the compiler. For example:
- The compiler will generate an error if we try to assign a value of the wrong type to a variable. If
x
is an integer, then we can't change its value to be aCow
. Since the compiler is the only one that knows thatx
is an integer, it's the only one that can stop us from doing bad things with types! - The compiler may offer a warning if we try to do an assignment (either with an
=
or by passing a value to a function) that will cause conversion to happen. In most cases, the compiler won't stop us from doing potentially dubious things with the values of our numeric variables, but most modern compilers will give us a heads up if they see us doing something questionable. - The compiler will generate an error if we try to use a variable in a way that doesn't make sense for its type. It's okay to add two integers together. it's not okay to add two
Cows
together. (What would that even mean?!)
I just ignore compiler warnings. Usually my program still works.
Don't. Ignoring compiler warnings usually means that there is a big red flag in what we're doing, often leading to subtle problems later that are hard to figure out.
The compiler also uses type information to decide how to translate certain steps into assembly (and, eventually, machine) code. For example:
- The compiler needs to figure out how big each variable is. Then it writes the instruction saying how much space should be allocated on the stack when the function begins.
- The compiler needs to figure out which version of certain functions and operations need to be run. For example, integers get added slightly differently than floating point numbers. The compiler decides how each step in the C++ source code should get translated to machine code.
I heard that C++ was “statically typed”. Is that related to what you're saying?
The word static is a fancy computer science term meaning “at compile time”. So, yes, that's a fancy way of saying that all of the type-checking is done at compile time.
The Compiler Handles Names
Similarly, variable names aren't stored anywhere in memory at run time. In the compiled code, names are replaced with ways to refer to particular memory locations (e.g., “stack slot S3”).
Thus, all errors that have to do with the name of variables come from the compiler. For example, the compiler will generate an error if we try to use the name of a variable when that variable is not in its use phase.
More formally, the part of our code where a variable's name (i.e., where the variable exists and has a value of some kind) is called its scope.
So, the scope of a variable name is from the point it was declared until the closing curly brace of the block it was declared in?
That's right!
The Compiler Checks Syntax
Since the compiler has to translate from C++ to assembly (and then to object code), it will be the one to check that your syntax is right.
So if I miss a semicolon, or have wrong number of parentheses?
The compiler will call you out!
Let's go over it just to be sure…
- (a) Has a type error that will be caught by the compiler. If
x
is a string, then it can't change into anint
. - (b) Has a typo in the name of
myvar
on the second line. The compiler won't know whatmzvar
is, which will cause it to report an error. - (c) Has a divide-by-zero error, but we won't find out about that until runtime. The compiler will be able to successfully translate each line into machine instructions.
- (d) Is missing a semicolon at the end of the first line. C++ doesn't pay attention to whitespace like line breaks, so we need the semicolons to separate expressions. Without the semicolon, the compiler won't know how to break the code into separate expressions to translate, and it will report an error.
(When logged in, completion status appears here.)