Basic Syntax & Types¶
In C++, understanding the core type system and variable semantics is crucial for writing efficient and safe code. Because C++ is a strongly-typed and statically-typed language, the compiler must know the type of every entity at compile time.
1. Comments and Code Documentation¶
Comments are ignored by the compiler but are essential for humans reading the codebase. Modern C++ codebases typically use two comment formats:
Doxygen Documentation Style¶
For professional C++ libraries, comments are often parsed by documentation generators like Doxygen. Use three slashes /// or a block starting with /** to generate API documentation:
2. Variables and Modern Initialization¶
A variable is a named memory location. Modern C++ (C++11 and later) introduced Brace Initialization (also called Uniform Initialization) to unify initialization syntax across all types.
Initialization Styles in C++¶
Why You Should Prefer Brace Initialization {}¶
- Prevents Narrowing Conversions: The compiler will raise an error if you attempt to assign a value that cannot fit into the target type without loss of precision.
- Avoids the "Most Vexing Parse": Sometimes, standard parentheses syntax can be mistaken by the compiler as a function declaration rather than object initialization. Brace syntax avoids this confusion.
3. Type Deduction (auto)¶
The auto keyword instructs the compiler to automatically deduce the type of a variable from its initializer expression. This is resolved at compile time, meaning there is zero runtime overhead.
Important Gotcha: CV Qualifiers and References¶
By default, auto strips away const and reference qualifications (&).
Rule of Thumb:
- Use auto for primitive types when the type is obvious.
- Use const auto& for complex objects (like classes and STL containers) to prevent expensive copy operations.
4. Fundamental Types and Platform Architecture¶
C++ provides native types whose sizes are implementation-dependent. When programming on a Raspberry Pi, the word size depends on whether you run a 32-bit (ARMhf) or 64-bit (ARM64) OS.
Standard Integer Types¶
| Type | Typical Size (ARM64 / 64-bit OS) | Range (Signed) | Description |
|---|---|---|---|
char |
1 byte | -128 to 127 | Stores ASCII values / characters |
short |
2 bytes | -32,768 to 32,767 | Small integers |
int |
4 bytes | ~ ±2.14 Billion | Default standard integer |
long |
8 bytes (4 bytes on 32-bit) | ~ ±9.22 Quintillion | Platform-dependent integer |
long long |
8 bytes | ~ ±9.22 Quintillion | Guaranteed to be at least 64-bit |
[!NOTE] To use integers with guaranteed bit-widths across different systems (essential for embedded and hardware-level programming), include
<cstdint>and use fixed-width types: -int8_t,int16_t,int32_t,int64_t(Signed) -uint8_t,uint16_t,uint32_t,uint64_t(Unsigned)
Floating-Point Types¶
| Type | Size | Precision | Typical Usage |
|---|---|---|---|
float |
4 bytes | ~7 decimal digits | Fast calculations, GPU usage |
double |
8 bytes | ~15 decimal digits | Default for floating-point literals |
long double |
8/16 bytes | Platform-dependent | High precision math |
5. Modern Constants: const vs constexpr vs consteval¶
Modern C++ has robust mechanisms to declare constant values and evaluate expressions at compile time.
const: Stands for "read-only." Its value can be determined at runtime, but once initialized, it cannot be modified.constexpr: Tells the compiler that the value can be computed at compile time. This allows the compiler to optimize out the calculation and embed the result directly in the binary.consteval(C++20): Implies that the function/expression must be evaluated at compile time. It is a compile error if it cannot be.
6. Structured Bindings (C++17)¶
Structured bindings allow you to unpack objects, arrays, or tuples into separate variables using a clean syntax.
7. Type Aliases (using)¶
C++ allows you to create aliases for complex types. While the older C-style typedef is still valid, the modern using syntax is preferred because it is more readable and supports templates.
8. Type Conversions and Casting¶
Avoid implicit type conversions that might hide bugs. When you need to cast one type to another, use C++ explicit cast operators rather than C-style casts.
Why Avoid C-style Casts?¶
C-style casts (int)value are aggressive. They try a static_cast, a const_cast, and a reinterpret_cast behind the scenes, which can lead to silent bugs.
Explicit C++ Casts¶
static_cast: The most common cast. Used for safe compile-time conversions (e.g.doubletoint,floattodouble).const_cast: Used to strip away theconstqualifier of a variable (use with caution).reinterpret_cast: Casts any pointer type to any other pointer type. Used for low-level memory operations (e.g. mapping physical register addresses).
Related Guides¶
- Control Flow — Conditional logic and loops.
- Pointers and References — Dive into pointer types and memory addresses.