Skip to content

📦 Variables & Data Types

Trong C++, mỗi biến có kiểu dữ liệu cố định quyết định kích thước bộ nhớ và phạm vi giá trị. Hiểu rõ types là bước đầu tiên để tối ưu performance.

Primitive Types — Các kiểu nguyên thủy

Integer Types

cpp
#include <iostream>
#include <climits>  // Chứa INT_MAX, INT_MIN, etc.

int main() {
    // Signed integers (có dấu)
    short s = 32767;           // Thường 2 bytes
    int i = 2147483647;        // Thường 4 bytes
    long l = 2147483647L;      // Ít nhất 4 bytes
    long long ll = 9223372036854775807LL;  // Ít nhất 8 bytes
    
    // Unsigned integers (không dấu)
    unsigned int ui = 4294967295U;  // Gấp đôi range của int
    
    std::cout << "sizeof(short): " << sizeof(short) << " bytes" << std::endl;
    std::cout << "sizeof(int): " << sizeof(int) << " bytes" << std::endl;
    std::cout << "sizeof(long): " << sizeof(long) << " bytes" << std::endl;
    std::cout << "sizeof(long long): " << sizeof(long long) << " bytes" << std::endl;
    
    std::cout << "INT_MAX: " << INT_MAX << std::endl;
    std::cout << "INT_MIN: " << INT_MIN << std::endl;
    
    return 0;
}

Bảng kích thước tiêu chuẩn (x64):

TypeSize (bytes)Range
short2-32,768 → 32,767
int4-2.1B → 2.1B
long4 hoặc 8Platform-dependent
long long8±9.2 × 10¹⁸
unsigned int40 → 4.3B

⚠️ Integer Overflow

cpp
int x = INT_MAX;  // 2147483647
x = x + 1;        // 💥 Overflow! x = -2147483648 (undefined in signed)

unsigned int u = 0;
u = u - 1;        // u = 4294967295 (wraps around)

Floating-Point Types

cpp
#include <iostream>
#include <iomanip>   // Cho std::setprecision
#include <cfloat>    // FLT_MAX, DBL_MAX

int main() {
    float f = 3.14159265358979f;    // 4 bytes, ~7 chữ số precision
    double d = 3.14159265358979;    // 8 bytes, ~15-16 chữ số precision
    long double ld = 3.14159265358979L;  // 8-16 bytes (platform-dependent)
    
    std::cout << std::setprecision(20);
    std::cout << "float:       " << f << std::endl;
    std::cout << "double:      " << d << std::endl;
    std::cout << "long double: " << ld << std::endl;
    
    std::cout << "\nSizes:" << std::endl;
    std::cout << "sizeof(float): " << sizeof(float) << " bytes" << std::endl;
    std::cout << "sizeof(double): " << sizeof(double) << " bytes" << std::endl;
    
    return 0;
}

Output:

float:       3.1415927410125732422
double:      3.1415926535897900074
long double: 3.1415926535897900074

Sizes:
sizeof(float): 4 bytes
sizeof(double): 8 bytes

🎓 Floating-Point Precision

Lưu ý float chỉ chính xác ~7 chữ số! Với tiền bạc, đừng bao giờ dùng float/double — dùng int (đơn vị cents) hoặc thư viện decimal.


Character & Boolean

cpp
#include <iostream>

int main() {
    // char — 1 byte, lưu 1 ký tự hoặc số -128 → 127
    char c = 'A';
    char num = 65;  // Cũng là 'A' (ASCII code)
    
    std::cout << "char c: " << c << std::endl;           // A
    std::cout << "char num: " << num << std::endl;       // A
    std::cout << "int(c): " << static_cast<int>(c) << std::endl;  // 65
    
    // bool — thường 1 byte, chỉ true/false
    bool isActive = true;
    bool isEmpty = false;
    
    std::cout << "sizeof(bool): " << sizeof(bool) << " bytes" << std::endl;
    std::cout << "true as int: " << isActive << std::endl;   // 1
    std::cout << "false as int: " << isEmpty << std::endl;   // 0
    
    // bool trong điều kiện
    int x = 42;
    if (x) {  // Bất kỳ non-zero nào cũng là true
        std::cout << "x is truthy!" << std::endl;
    }
    
    return 0;
}

Type Modifiers

cpp
#include <iostream>

int main() {
    // signed (mặc định cho int)
    signed int a = -100;
    
    // unsigned — không âm, range gấp đôi
    unsigned int b = 4000000000U;
    
    // short — nhỏ hơn
    short int c = 30000;
    
    // long — lớn hơn
    long int d = 2000000000L;
    long long int e = 9000000000000000000LL;
    
    // Có thể bỏ "int"
    unsigned u = 100;
    long l = 200L;
    
    std::cout << "unsigned int max: " << b << std::endl;
    std::cout << "long long: " << e << std::endl;
    
    return 0;
}

Modern C++: auto Keyword (C++11)

auto cho phép compiler suy luận kiểu từ giá trị khởi tạo:

cpp
#include <iostream>
#include <vector>
#include <string>

int main() {
    // auto suy luận từ literal
    auto x = 42;          // int
    auto y = 3.14;        // double
    auto c = 'A';         // char
    auto str = "Hello";   // const char* (KHÔNG phải std::string!)
    
    // auto với std::string
    auto name = std::string("PENALGO");  // std::string
    
    // auto RẤT hữu ích với iterators
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    
    // Thay vì:
    // std::vector<int>::iterator it = numbers.begin();
    
    // Dùng auto:
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    
    // Range-based for với auto (C++11)
    for (auto& num : numbers) {  // auto& để modify
        num *= 2;
    }
    
    for (const auto& num : numbers) {  // const auto& để read-only
        std::cout << num << " ";
    }
    std::cout << std::endl;
    
    return 0;
}

📌 HPN Standard: Khi nào dùng auto?

SituationRecommendation
Iterator types✅ Luôn dùng auto
Lambda expressions✅ Bắt buộc auto
Complex template types✅ Dùng auto cho readable
Literals đơn giản (auto x = 42;)⚠️ Có thể, nhưng explicit type rõ ràng hơn
Function return type⚠️ Cân nhắc — có thể khó đọc

Fixed-Width Integer Types (C++11)

Để đảm bảo kích thước chính xác trên mọi platform:

cpp
#include <iostream>
#include <cstdint>  // int8_t, int16_t, int32_t, int64_t

int main() {
    // Guaranteed exact width
    int8_t  a = 127;           // Exactly 8 bits  (1 byte)
    int16_t b = 32767;         // Exactly 16 bits (2 bytes)
    int32_t c = 2147483647;    // Exactly 32 bits (4 bytes)
    int64_t d = 9223372036854775807LL;  // Exactly 64 bits (8 bytes)
    
    // Unsigned versions
    uint8_t  ua = 255;
    uint16_t ub = 65535;
    uint32_t uc = 4294967295U;
    uint64_t ud = 18446744073709551615ULL;
    
    std::cout << "int8_t size: " << sizeof(int8_t) << std::endl;   // 1
    std::cout << "int32_t size: " << sizeof(int32_t) << std::endl; // 4
    std::cout << "int64_t size: " << sizeof(int64_t) << std::endl; // 8
    
    return 0;
}

📌 Best Practice

  • API/Network data: Dùng int32_t, uint64_t để đảm bảo cross-platform
  • Loop counters: int hoặc size_t (cho array indices)
  • IDs từ database: int64_t hoặc uint64_t

Type Casting

cpp
#include <iostream>

int main() {
    // Implicit conversion (tự động)
    int i = 42;
    double d = i;  // 42.0 — OK, không mất data
    
    double pi = 3.14159;
    int truncated = pi;  // 3 — ⚠️ Mất phần thập phân!
    
    // Explicit casting với static_cast (Modern C++)
    double result = static_cast<double>(5) / 2;  // 2.5
    int rounded = static_cast<int>(pi);          // 3
    
    // C-style cast (không khuyên dùng)
    int c_style = (int)pi;  // Works nhưng less safe
    
    std::cout << "d: " << d << std::endl;
    std::cout << "truncated: " << truncated << std::endl;
    std::cout << "result: " << result << std::endl;
    
    return 0;
}

🐛 Spot the Bug: Type Edition

🐛 Bug Hunt Challenge

Output của chương trình sau là gì?

cpp
#include <iostream>

int main() {
    unsigned int a = 10;
    int b = -20;
    
    if (a + b > 0) {
        std::cout << "Positive!" << std::endl;
    } else {
        std::cout << "Negative or zero!" << std::endl;
    }
    
    return 0;
}
💡 Gợi ý

Khi signed gặp unsigned trong biểu thức, chuyện gì xảy ra?

🔍 Giải thích chi tiết

Output: Positive! 😱

Tại sao? Khi mix signedunsigned:

  1. b (-20) được convert sang unsigned
  2. -20 trong unsigned 32-bit = 4294967276
  3. 10 + 4294967276 = 4294967286 > 0 → Positive!

Fix:

cpp
if (static_cast<int>(a) + b > 0) { ... }
// Hoặc tốt hơn: dùng cùng type cho cả hai

📚 Tổng kết

ConceptKey Takeaway
Primitive typesint, float, double, char, bool — biết size của từng loại
sizeof()Cho biết kích thước chính xác (bytes)
Type modifierssigned, unsigned, short, long — thay đổi range
auto (C++11)Compiler suy luận type — useful cho iterators
Fixed-widthint32_t, uint64_t — guaranteed size
Mixing signed/unsigned⚠️ Nguy hiểm! Avoid hoặc cast explicitly

➡️ Tiếp theo

Bạn đã hiểu Data Types. Tiếp theo: Pointers & References — Phần quan trọng nhất của C++!