Menu

Kiểu dữ liệu trong C++: int, double, char, bool và hơn thế

Tìm hiểu thực tế các kiểu dữ liệu cơ bản của C++: số nguyên, số thực, char và bool, cùng kích thước, signed và unsigned, literal và hậu tố, tràn số và cách chọn đúng kiểu.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Vì sao kiểu dữ liệu quan trọng trong C++

Khi bạn khai báo một giá trị với kiểu rõ ràng như int age = 30;, kiểu đó không chỉ là cái nhãn: nó cho trình biên dịch biết cần dành bao nhiêu byte, hiểu các byte đó ra sao và phép toán nào hợp lệ. Chọn sai kiểu, bạn có thể âm thầm mất độ chính xác, bị tràn số hoặc gây ra undefined behavior.

C++ chia các kiểu dữ liệu (data type) có sẵn thành vài nhóm: số nguyên, số thực dấu phẩy động, kiểu ký tự và kiểu boolean. Ta sẽ xem từng nhóm, rồi đến những quy tắc hay làm người học vấp.

Các kiểu cơ bản

Đây là một ví dụ cho mỗi kiểu cốt lõi trong cùng một chương trình. Để ý các hậu tố của literal (L, f, u) và dấu nháy đơn của char:

Theo mặc định, bool được in ra là 1 hoặc 0, không phải true/false. char dùng dấu nháy đơn: 'A' là một ký tự, còn "A" (nháy kép) là một literal chuỗi, một kiểu hoàn toàn khác. Hai lỗi này cực kỳ phổ biến lúc mới học.

Kích thước không cố định

Đây là điều bất ngờ nhất với ai đến từ những ngôn ngữ như Java. Chuẩn C++ chỉ bảo đảm kích thước tối thiểu và thứ tự tương đối (short ≤ int ≤ long ≤ long long). Kích thước thực tế tùy vào trình biên dịch và nền tảng. Luôn kiểm tra bằng sizeof:

Trên một bản build Linux 64 bit thông thường, bạn sẽ thấy int = 4, long = 8. Nhưng trên Windows 64 bit, long chỉ có 4 byte. Khác biệt về tính di động đó chính là lý do bạn không nên viết code giả định long là 64 bit.

Khi cần độ rộng chính xác, hãy dùng các kiểu số nguyên có độ rộng cố định trong <cstdint>:

Dùng int32_t/int64_t cho định dạng tệp, giao thức mạng hoặc bất cứ thứ gì phải chạy giống hệt nhau trên mọi máy. Để ý phép ép kiểu (int)a: đưa một kiểu 8 bit vào luồng xuất sẽ in ra ký tự chứ không phải số, nên cần ép kiểu trước.

Signed và unsigned

Mỗi kiểu số nguyên có hai dạng. Kiểu signed chứa được số âm; kiểu unsigned thì không, đổi phần miền âm lấy giá trị dương tối đa lớn hơn. int thường mặc định là signed.

Trừ đi từ một số unsigned bằng 0 sẽ quay vòng thành một số dương khổng lồ thay vì thành số âm. Lỗi này xảy ra liên tục, nhất là với size_t (một kiểu unsigned) mà .size() trả về:

vector<int> v = {1, 2, 3};
// DANGER: v.size() is unsigned. If v is empty, v.size() - 1 wraps
// to a gigantic number and the loop runs nearly forever.
for (size_t i = 0; i <= v.size() - 1; i++) { /* ... */ }

Hãy dùng i < v.size() (đừng bao giờ dùng <= size() - 1), hoặc tránh hẳn vấn đề bằng vòng lặp for theo phạm vi.

Tràn số nguyên là undefined behavior

Khác với việc quay vòng của số unsigned (vốn được định nghĩa rõ), tràn số nguyên signed là undefined behavior trong C++. Trình biên dịch được phép làm bất cứ điều gì: trả về giá trị rác, tối ưu bỏ luôn phép kiểm tra, hoặc làm chương trình sập:

Cách sửa giống bẫy tràn số ở mọi ngôn ngữ: tính toán trong một kiểu rộng hơn. Ép một toán hạng sang long long trước phép +, để phép cộng diễn ra trong 64 bit. Ép kiểu kết quả sau đó là quá muộn, vì tràn số đã xảy ra rồi.

Chọn đúng kiểu

Với phần lớn code, các lựa chọn mặc định là đủ: int cho số nguyên, double cho số thập phân. Chỉ dùng kiểu khác khi bạn có lý do.

KiểuKích thước thường gặpDùng khi
int32 bitLựa chọn mặc định cho số nguyên
long long64 bitGiá trị vượt khoảng 2 tỷ: timestamp, bộ đếm lớn
double64 bitLựa chọn mặc định cho số thập phân, độ chính xác tốt
float32 bitMảng cần tiết kiệm bộ nhớ, chấp nhận kém chính xác
bool1 byteCờ đúng/sai
int32_t / int64_tchính xácĐịnh dạng đa nền tảng, giao thức, thao tác bit

Vài điểm dễ nhầm cần nhớ. float chỉ có khoảng 7 chữ số thập phân có nghĩa, nên 0.1f + 0.2f không đúng bằng 0.3; hãy ưu tiên double trừ khi bạn thật sự cần tiết kiệm bộ nhớ. Và char có thể là signed hoặc unsigned tùy nền tảng, nên nếu làm phép tính trên byte thô, hãy viết rõ signed char hoặc unsigned char.

Tiếp theo: từ khóa auto

Lần nào cũng viết đầy đủ kiểu thì khá mệt, và đôi khi tên kiểu rất dài hoặc khó gọi tên. C++ cho phép trình biên dịch tự suy ra kiểu bằng từ khóa auto: auto x = 42; khiến x là int, còn auto it = v.begin(); giúp bạn khỏi gõ một kiểu iterator dài dòng. Trang tiếp theo trình bày khi nào auto làm code rõ hơn và khi nào nó che giấu quá nhiều.

Câu hỏi thường gặp

C++ có những kiểu dữ liệu cơ bản nào?

Các kiểu cơ bản gồm số nguyên (short, int, long, long long), số thực (float, double, long double), kiểu ký tự char và kiểu boolean bool. Mỗi kiểu số nguyên còn có thể là signed hoặc unsigned. Mọi thứ khác, như std::string, mảng hay lớp do bạn tự viết, đều được xây trên các kiểu này.

int và long trong C++ khác nhau thế nào?

Cả hai đều lưu số nguyên, nhưng long được bảo đảm rộng ít nhất bằng int (thường là 64 bit trên nền tảng 64 bit, nhưng chỉ 32 bit trên Windows). Chuẩn C++ chỉ quy định kích thước tối thiểu, nên khi cần độ rộng chắc chắn, hãy dùng các kiểu có độ rộng cố định trong <cstdint> như int32_t và int64_t.

Kiểu int trong C++ lớn bao nhiêu?

Chuẩn chỉ bảo đảm int có ít nhất 16 bit, nhưng trên hầu hết máy tính để bàn và máy chủ hiện đại, nó là 32 bit. Vì kích thước phụ thuộc nền tảng, đừng bao giờ đoán: in sizeof(int) ra để kiểm tra, hoặc dùng các kiểu trong <cstdint> như int32_t khi cần độ rộng chính xác.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu