Constants and Symbolic Names
Integer, floating, character, and string literals, const-qualified variables, and #define symbolic constants and when to use each.
Numbers That Never Change Still Deserve Names
Every program is full of fixed values: the 100.0 in the interest formula, the mathematical pi, the size of something. C gives you three distinct tools here: literal constants for writing values, const for variables that must not change, and #define for naming a value before compilation even starts. Exams love to ask the difference; so does real code review.
Integer Constants, in Three Bases
An integer constant is normally decimal: 42, -7, 100000. Two prefixes change the base, and both are exam regulars:
- A leading
0means octal (base 8):010is eight, not ten. - A leading
0xor0Xmeans hexadecimal (base 16):0x1Fis thirty-one.
The octal rule is a genuine trap. Write int code = 052; intending fifty-two, and you have written forty-two. Never left-pad integer constants with zeros.
Suffixes select a type when it matters: 100L is a long constant, 100U unsigned, 100UL both. Without a suffix, a small integer constant is an int.
All three lines print 42, one value written in three notations. printf can also output in the other bases: %o prints octal, %x hexadecimal.
Floating and Character Constants
A floating constant contains a decimal point (3.14159, 0.5), and may use exponent notation: 2.5e3 is 2500.0, 1e-2 is 0.01. Its type is double unless a suffix says otherwise: f makes it a float (3.14f) and l a long double (3.14l). Write those suffixes as capitals, 3.14F and 3.14L, for the same reason the integer suffix is written 100L: a lowercase l and the digit 1 are indistinguishable in too many fonts.
A character constant is one character in single quotes: 'A', '7', '%'. Escape sequences count as one character: '\n', '\t', and the one that will matter enormously in the strings chapter, '\0', the character whose code is zero. Remember from last lesson that these are small integers: 'A' is 65, '0' is 48, and '0' and 0 are different values. Double quotes make a string literal instead; 'A' and "A" are different things entirely, which the strings chapter unpacks.
The Escape Sequences in Full
Some characters cannot be written literally between quotes. A newline would end the line, a double quote would end the string, and several have no printable shape at all. C spells them with a backslash, and each of these two-character sequences is one character in the compiled program:
| Sequence | Character |
|---|---|
\n |
newline |
\t |
horizontal tab |
\v |
vertical tab |
\b |
backspace |
\r |
carriage return |
\f |
form feed |
\a |
alert (the terminal bell) |
\\ |
backslash |
\' |
single quote |
\" |
double quote |
\? |
question mark |
\0 |
the character whose code is zero |
The whole table is standard exam material, but the working set is smaller than it looks. You will use \n constantly, \t for columns, and \0 throughout the strings chapter. \\ and \" exist because those two characters would otherwise be read as syntax rather than data. \' is only needed inside a character constant, where '\'' is the apostrophe, and \" only inside a string literal; each is harmless but redundant in the other. \? was invented to stop a ?? pair being mistaken for one of ANSI C's trigraph spellings, a problem no modern keyboard has. And \a, \b, \r, and \f are terminal control rather than text: what they do to your screen depends on the terminal, so no course example depends on them.
\0 is not a special rule but the shortest case of a general one: \ooo is a character given in octal and \xhh one given in hexadecimal, so '\101' and '\x41' are both 'A'.
tab: after the tab
quote: " backslash: \ apostrophe: '
a literal percent sign: 100%
The last line is a different mechanism wearing similar clothes. \\ is resolved by the compiler, which puts one backslash character into the string; %% is resolved by printf at run time, which reads the format string looking for % and needs a way to be told "print one of these". A lone % in a format string is a bug rather than an escape, and the printf chapter is where that distinction earns its keep.
const: A Variable That Refuses Assignment
Qualifying a declaration with const makes assignment to it illegal after initialization:
const double rate = 7.5;
rate = 9.0; /* compile error: assignment of read-only variable */
const documents intent and recruits the compiler to enforce it. Everything else about the variable is unchanged: it has an address, a size, a type, and it obeys the declarations-first rule.
volatile: A Value That Changes Behind Your Back
const is one of ANSI C's two type qualifiers. The other is volatile, and it makes almost the opposite promise:
volatile int sensorReading;
This tells the compiler that the object may be changed by something outside the flow of this program: a hardware register wired to a sensor, a location another device writes, a variable a signal handler touches. The consequence is a restriction on optimization. Ordinarily a compiler may keep a value in a register and reuse it, or delete a read whose result cannot have changed since the last one; for a volatile object it must perform every read the source asks for, in the order written.
What volatile does not do deserves saying plainly, because it attracts more folklore than any other qualifier. It is not atomicity and it is not a synchronization mechanism: it says nothing about whether a read and a write can overlap, only that reads and writes are really performed. Code that needs safety between concurrent tasks needs tools ANSI C does not contain.
Course programs need none of this, because nothing here talks to hardware. The reasons to meet it now are that you will see it in the keyword list and should not have to wonder, and that exam papers like to slip it into a list of storage classes to see whether you know it is a qualifier instead. Both qualifiers can apply at once:
const volatile int deviceStatus;
The program may not write it, and must re-read it every time. For a read-only hardware register that is exactly the right pair of statements.
#define: Naming Text Before Compilation
The preprocessor offers a different mechanism:
#define PI 3.14159
This is not a declaration; it is an instruction to the preprocessor: before compiling, replace every later token PI with the text 3.14159. No memory, no type, no semicolon. The convention, near-universal since the language began, is UPPER_CASE names for defined constants, which is why they are often called symbolic constants.
By the time the compiler runs, the printf line reads 3.14159 * radius * radius. The name PI no longer exists.
const or #define?
For a beginner's rule of thumb: prefer const for typed program values, and use #define where a name must exist before compilation or must be a true compile-time constant. In ANSI C that second category is real: a const variable is still a variable, so contexts demanding a constant expression, array sizes chief among them, when you reach them, accept #define PI but reject const double pi. The two tools also fail differently: a mistyped const gives a clear error at its declaration, while a mistyped #define produces errors at every use site, reported in code that looks innocent. Exam answers should mention the deepest difference: #define is textual substitution by the preprocessor; const is a typed variable the compiler protects.
Key Takeaways
- Integer constants: decimal by default,
0prefix means octal (a classic trap),0xmeans hexadecimal; suffixesUandLselect type. - Floating constants are
doubleunless suffixed:Fforfloat,Lforlong double; exponent form2.5e3is available. - Character constants are single-quoted single characters;
'A'is the integer 65;'0'is not0;'\0'is the zero-code character. - Escape sequences are one character each:
\n \t \v \b \r \f \a \\ \' \" \? \0, with\oooand\xhhfor any code you like.\\is the compiler's doing;%%isprintf's. constdeclares a real, typed variable that rejects assignment after initialization.volatileis the other type qualifier, not a storage class: it forbids the compiler from caching or eliminating reads, and promises nothing about atomicity.#define NAME valueis preprocessor text substitution: no type, no memory, UPPER_CASE by convention.- Prefer
constfor typed values;#definewhere a compile-time constant or pre-compilation name is required.
How did you find this lesson?
Your rating helps us improve the content.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Constants and Symbolic Names - Quiz
Test your understanding of the lesson.
Practice Exercises
Circle Calculator with a Symbolic Constant
Define PI as a symbolic constant with #define, read a radius, and print the circle's area and circumference with two decimal places. Area is PI * radius * radius; circumference is 2 * PI * radius.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!