ข้ามไปที่เนื้อหา

Ch3: Variables and data types

TL;DR: Memory Representation: ข้อมูลทั้งหมดใน C++ จะเก็บเป็นเลขฐานสอง (Bit กลุ่มกันเป็น Byte) โดยเลขฐานแปด (Octal) และสิบหก (Hexadecimal) เป็นเพียงแค่รูปแบบแสดงผลเพื่อให้มนุษย์อ่านได้สะดวก

⚡ Quick Reference

#include <iostream>
#include <limits>

int main() {
    // int x {5}; - ใช้ Brace initialization สำหรับกำหนดค่าเริ่มต้นแบบ Uniform
    int a {5};
    int b {}; // กำหนดค่าเริ่มต้นเป็น 0 (Zero-initialization)

    // double, float, char, bool - ตัวแปรประเภทข้อมูลพื้นฐานต่างๆ
    double d {3.14};
    float f {2.5f};
    char c {'A'};
    bool ok {true};

    // sizeof(type) - คำนวณหาขนาดของชนิดข้อมูลหรือตัวแปรในหน่วย Byte
    std::cout << sizeof(int) << std::endl;

    // signed, unsigned, short, long, long long - ตัวดัดแปลงขนาดและเครื่องหมายของจำนวนเต็ม
    short int si {10};
    long int li {100};
    long long int lli {1000};
    unsigned int ui {50u};

    // const - ป้องกันไม่ให้แก้ไขค่าของตัวแปรหลังจากสร้างขึ้นมาแล้ว
    const int limit = 100;

    // auto - ให้คอมไพเลอร์คาดเดาประเภทข้อมูลจากค่าเริ่มต้นโดยอัตโนมัติ
    auto value = 15.5;

    // std::numeric_limits<T>::min() - ดึงค่าต่ำสุดและสูงสุดที่เป็นไปได้ของแต่ละประเภทข้อมูล
    std::cout << std::numeric_limits<int>::min() << std::endl;

    return 0;
}

🧠 Core Concepts

  • Memory Representation: ข้อมูลทั้งหมดใน C++ จะเก็บเป็นเลขฐานสอง (Bit กลุ่มกันเป็น Byte) โดยเลขฐานแปด (Octal) และสิบหก (Hexadecimal) เป็นเพียงแค่รูปแบบแสดงผลเพื่อให้มนุษย์อ่านได้สะดวก
  • Initialization Safety: การประกาศตัวแปรแบบใช้ปีกกา ({}) จะป้องกันการแปลงข้อมูลที่ทำให้สูญเสียความละเอียด (Narrowing conversion) ตั้งแต่ตอน Compile ขณะที่แบบวงเล็บ (()) และแบบเครื่องหมายเท่ากับ (=) จะปัดเศษทิ้งอย่างเงียบๆ
  • Type Deduction: Keyword auto ช่วยให้ Compiler สามารถคาดเดาประเภทข้อมูลจากค่าเริ่มต้นได้ตอน Compile โดยใช้ Literal Suffix (เช่น f, u, ll) ในการระบุประเภทเฉพาะเจาะจง ซึ่งประเภทนี้จะถูกฟิกซ์ไว้และไม่สามารถเก็บข้อมูลประเภทอื่นในภายหลังได้

⚠️ Pitfalls (Quick Scan)

ข้อผิดพลาด วิธีแก้
การประกาศตัวแปรโดยไม่ได้กำหนดค่าเริ่มต้น ใช้ Braced Initialization เสมอ เช่น int elephant_count{};
การเกิด Narrowing จากวิธี Functional หรือ Copy initialization ใช้ Braced Initialization (int x{2.9};) เพื่อบังคับให้เกิด Compile error เมื่อข้อมูลลดรูป
ความสับสนในการใช้เลข 0 นำหน้าตัวเลขธรรมดา ห้ามใส่เลข 0 นำหน้าเลขฐานสิบ และใช้ 0x หรือ 0b ในฐานอื่นแทน
การลืมใส่ Suffix f สำหรับค่าประเภท float ใส่ Suffix f เสมอเมื่อระบุค่าทศนิยมให้กับตัวแปรประเภท float
การกำหนดค่าติดลบให้กับตัวแปร unsigned ที่ถูกประกาศผ่าน auto เลี่ยงการใช้ auto ร่วมกับ Suffix u หากมีโอกาสที่ตัวแปรจะได้รับค่าติดลบในภายหลัง
การเปลี่ยนค่าตัวแปรประเภท auto ด้วยรูปแบบข้อมูลที่ขัดแย้งกัน ระบุประเภทข้อมูลของตัวแปรตรงๆ หากค่านั้นจำเป็นต้องเก็บประเภทข้อมูลที่ต่างกันออกไป
การนำ 0.0 หารด้วย 0.0 ตรวจสอบตัวหารก่อนทำประมวลผลทางคณิตศาสตร์เสมอ
การใช้ตัวเลขเกินข้อจำกัดความละเอียดของชนิดข้อมูลทศนิยม เลือกชนิดข้อมูลทศนิยมให้เหมาะสมกับความละเอียดที่ต้องการใช้งาน และเลี่ยงการเปรียบเทียบทศนิยมตรงๆ

📖 Full Details

Cause → Effect → Fix พร้อม timestamp (คลิกเพื่อดู) * **การประกาศตัวแปรโดยไม่ได้กำหนดค่าเริ่มต้น** -> **การอ่านค่าขยะใน Memory มาใช้งานจะทำให้เกิด Undefined behavior** -> **ใช้ Braced Initialization เสมอ เช่น `int elephant_count{};` (8:50)** * **การเกิด Narrowing จากวิธี Functional หรือ Copy initialization** -> **ทศนิยมจะถูกตัดเศษทิ้งอย่างเงียบๆ (เช่น `2.9` เหลือ `2`) ทำให้ข้อมูลสูญหาย** -> **ใช้ Braced Initialization (`int x{2.9};`) เพื่อบังคับให้เกิด Compile error เมื่อข้อมูลลดรูป (9:50)** * **ความสับสนในการใช้เลข 0 นำหน้าตัวเลขธรรมดา** -> **Compiler จะมองว่าเป็นเลขฐานแปด (Octal) ทำให้ได้ค่าไม่ตรงกับที่คิด (เช่น `017` มีค่าเท่ากับ `15` ในฐานสิบ)** -> **ห้ามใส่เลข 0 นำหน้าเลขฐานสิบ และใช้ `0x` หรือ `0b` ในฐานอื่นแทน (6:11)** * **การลืมใส่ Suffix `f` สำหรับค่าประเภท `float`** -> **ตัวเลขจะถูกมองเป็น `double` ก่อนจะตัดรูปมาเป็น `float` ทำให้เสี่ยงสูญเสียความละเอียด** -> **ใส่ Suffix `f` เสมอเมื่อระบุค่าทศนิยมให้กับตัวแปรประเภท `float` (24:38)** * **การกำหนดค่าติดลบให้กับตัวแปร `unsigned` ที่ถูกประกาศผ่าน `auto`** -> **Compiler ยอมทำงานและปัดค่ากลับมาเป็นบวกที่มีค่ามหาศาลแทน** -> **เลี่ยงการใช้ `auto` ร่วมกับ Suffix `u` หากมีโอกาสที่ตัวแปรจะได้รับค่าติดลบในภายหลัง (41:16)** * **การเปลี่ยนค่าตัวแปรประเภท `auto` ด้วยรูปแบบข้อมูลที่ขัดแย้งกัน** -> **Compiler จะบังคับแปลงค่าเหล่านั้นให้อยู่ในประเภทแรกที่คาดเดาไว้ ทำให้เกิดข้อมูลเพี้ยน** -> **ระบุประเภทข้อมูลของตัวแปรตรงๆ หากค่านั้นจำเป็นต้องเก็บประเภทข้อมูลที่ต่างกันออกไป (41:16)** * **การนำ 0.0 หารด้วย 0.0** -> **ได้ผลลัพธ์เป็น `NaN` (Not a Number) ซึ่งจะแพร่กระจายไปทำลายการคำนวณถัดๆ ไปทั้งหมด** -> **ตรวจสอบตัวหารก่อนทำประมวลผลทางคณิตศาสตร์เสมอ (24:22)** * **การใช้ตัวเลขเกินข้อจำกัดความละเอียดของชนิดข้อมูลทศนิยม** -> **ข้อมูลส่วนเกินขีดจำกัด (`~7` หลักสำหรับ `float`, `~15` หลักสำหรับ `double`) จะกลายเป็นค่าขยะ** -> **เลือกชนิดข้อมูลทศนิยมให้เหมาะสมกับความละเอียดที่ต้องการใช้งาน และเลี่ยงการเปรียบเทียบทศนิยมตรงๆ (25:58, 26:15)**

📎 Repo Files

  • 04.VariablesAndDatatypes/4.2NumberSystems/main.cpp
  • 04.VariablesAndDatatypes/4.3IntegerTypes/main.cpp
  • 04.VariablesAndDatatypes/4.4IntegerModifiers/main.cpp
  • 04.VariablesAndDatatypes/4.5FractionalNumbers/main.cpp
  • 04.VariablesAndDatatypes/4.6Booleans/main.cpp
  • 04.VariablesAndDatatypes/4.7CharactersAndText/main.cpp
  • 04.VariablesAndDatatypes/4.8Auto/main.cpp
  • 04.VariablesAndDatatypes/4.9Assignments/main.cpp