C Constants
What Are Constants?
A constant is a value that does not change during program execution. Using constants makes code safer, clearer, and less error-prone.
In C, you can create constants as: literal constants (e.g., 42, 3.14, 'A'), named constants using const, macro constants using #define, and sets of integer constants using enum.
Literal Constants (Numbers, Characters, Strings)
Integer literals can be written in decimal (e.g., 42), octal (prefix 0, e.g., 075), or hexadecimal (prefix 0x, e.g., 0x2A). Be careful with leading 0 in integers: it means octal.
Integer suffixes adjust type: U/u (unsigned), L/l (long), LL/ll (long long) and combinations (e.g., 10U, 10UL, 10LL).
Floating literals support fractional or exponential notation (e.g., 3.14, 1.0e-3). Suffixes: f/F (float), l/L (long double).
Character constants use single quotes (e.g., 'A', '\n'). String literals use double quotes and are arrays of char terminated by '\0'. Modifying a string literal is undefined behavior.
#include <stdio.h>
int main(void) {
printf("%d %d %d\n", 42, 010, 0x2A); // decimal, octal, hex
printf("%f %.2f %Lf\n", 3.14, 3.14159, 4.0L); // double, double, long double
printf("%c %d\n", 'A', 'A'); // 'A' as char and as code
printf("%s\n", "Hello World");
return 0;
}
42 8 42 3.140000 3.14 4.000000 A 65 Hello World
Kind | Examples | Notes |
---|---|---|
Integer | 42, 010, 0x2A, 100U, 100L, 100ULL | Octal prefix 0; Hex prefix 0x; suffix sets type |
Floating | 3.14, 2.0e3, 1.0f, 4.0L | f = float, (no suffix) = double, L = long double |
Character | 'A', '\n', '\t' | Character constants have type int; value is character code (often ASCII) |
String | "Hello", "A\nB" | Array of char with trailing '\0' (don’t modify) |
Named Constants with const
Use the const qualifier to make a variable read-only after initialization. It has type safety, scope, and debuggability.
Be careful with pointers: const can apply to the pointed-to value, the pointer itself, or both.
#include <stdio.h>
int main(void) {
const int DAYS_IN_WEEK = 7; // read-only after initialization
int x = 10;
const int *p = &x; // pointer to const int (can't change *p)
int * const q = &x; // const pointer to int (can't change q)
*q = 20; // OK: changing x via q
// *p = 30; // error: read-only through p
printf("%d %d\n", DAYS_IN_WEEK, x);
return 0;
}
7 20
Macro Constants with #define
#define creates a preprocessor replacement before compilation. It has no type and no scope rules; use parentheses in expressions.
Prefer const for typed values; use #define for conditional compilation or when a constant must be used in places the language forbids objects (e.g., array sizes in older C variants or in case labels).
#include <stdio.h>
#define TAX_RATE (0.18)
#define BUF_SIZE (1024)
int main(void) {
double price = 100.0;
double total = price * (1.0 + TAX_RATE);
char buf[BUF_SIZE];
(void)buf; // suppress unused warning
printf("%.2f\n", total);
return 0;
}
118.00
Enumerations (enum)
enum defines a set of named integer constants. By default values start at 0 and increment by 1, but you can assign explicit values.
Enumerators are integer constant expressions suitable for array sizes, case labels, etc.
#include <stdio.h>
int main(void) {
enum Color { RED, GREEN = 5, BLUE };
printf("%d %d %d\n", RED, GREEN, BLUE);
return 0;
}
0 5 6
Constant Expressions & Compile-Time Contexts
An *integer constant expression* is required in some contexts (e.g., case labels, bit-field widths, some array bounds).
Enumerators (from enum) are integer constant expressions. `#define` macros can also form constant expressions after substitution.
`const` variables are not integer constant expressions and generally cannot be used where a compile-time constant is required (use enum or macros instead), unless your compiler provides non-standard extensions.
Best Practices & Pitfalls
Use const for typed, scoped constants; prefer enum for related integer codes and compile-time integer constants; use #define for compile-time needs and conditional compilation.
Avoid modifying string literals: it is undefined behavior.
Give constants descriptive UPPER_SNAKE_CASE names for #define and clear names for const/enum.
Use explicit suffixes (U, L, LL, f, L) when ranges or precision matter.
Be cautious with leading 0 in integer literals (octal) to avoid accidental base-8 numbers.