Chuyển tới nội dung chính

Kiểu dữ liệu trong C++

Dưới đây là bảng liệt kê các kiểu dữ liệu thường dùng trong C++ cùng kích thước và phạm vi của chúng trong môi trường 32-bit và 64-bit (tuân theo chuẩn phổ biến hiện nay: LP32 và LLP64), bao gồm các kiểu dữ liệu định nghĩa bởi Windows API. Lưu ý rằng kích thước và phạm vi có thể phụ thuộc vào trình biên dịch và hệ điều hành, nhưng các giá trị dưới đây là phổ biến cho các hệ thống Windows.

Kiểu số nguyên có dấu (signed)

KiểuKích thước 32-bit/64-bitPhạm vi
char1 byte / 1 byte-128 đến 127 (mặc định signed trên MSVC, unsigned trên một số trình biên dịch khác)
short2 byte / 2 byte-32,768 đến 32,767
int4 byte / 4 byte-2,147,483,648 đến 2,147,483,647
long4 byte / 4 byte (Windows), 8 byte (Linux)-2,147,483,648 đến 2,147,483,647 (Windows)
long long8 byte / 8 byte-9,223,372,036,854,775,808 đến +9,223,372,036,854,775,807

Kiểu số nguyên không dấu (unsigned)

KiểuKích thướcPhạm vi
unsigned char1 byte0 đến 255
unsigned short2 byte0 đến 65,535
unsigned int4 byte0 đến 4,294,967,295
unsigned long4 byte (Win), 8 byte (Linux)0 đến 4,294,967,295 (Windows)
unsigned long long8 byte0 đến 18,446,744,073,709,551,615

Kiểu cố định kích thước (từ <cstdint>)

KiểuKích thướcPhạm vi
int8_t1 byte-128 đến 127
uint8_t1 byte0 đến 255
int32_t4 byte-2,147,483,648 đến 2,147,483,647
uint32_t4 byte0 đến 4,294,967,295
int64_t8 byte-9,223,372,036,854,775,808 đến 9,223,372,036,854,775,807
uint64_t8 byte0 đến 18,446,744,073,709,551,615

Kiểu thực (float, double)

KiểuKích thướcPhạm vi gần đúng
float4 byte~ ±1.2×10⁻³⁸ đến ±3.4×10³⁸
double8 byte~ ±2.3×10⁻³⁰⁸ đến ±1.7×10³⁰⁸
long double8 byte (MSVC), 10/16 byte (GCC)phạm vi lớn hơn double (phụ thuộc trình biên dịch)

Kiểu logic & ký tự

KiểuKích thướcGhi chú
bool1 byteChỉ nhận true hoặc false
char1 byteMã ASCII ký tự (signed trên MSVC, unsigned trên một số trình biên dịch)
wchar_t2 byte (Windows), 4 byte (Linux)Dùng cho ký tự Unicode rộng
char16_t2 byteUTF-16
char32_t4 byteUTF-32

Kiểu size và con trỏ

KiểuKích thước 32-bit/64-bitGhi chú
size_t4 byte / 8 byteKiểu unsigned dùng cho kích thước mảng
ptrdiff_t4 byte / 8 byteKiểu signed, dùng cho hiệu 2 con trỏ
void*4 byte / 8 byteKích thước con trỏ

Kiểm tra thực tế:

#include <iostream>
#include <typeinfo>
#include <cstddef>

int main() {
std::cout << "int: " << sizeof(int) << " bytes\n";
std::cout << "long: " << sizeof(long) << " bytes\n";
std::cout << "long long: " << sizeof(long long) << " bytes\n";
std::cout << "size_t: " << sizeof(size_t) << " bytes\n";
std::cout << "void*: " << sizeof(void*) << " bytes\n";
std::cout << "int32_t: " << sizeof(int32_t) << " bytes\n";
std::cout << "uint64_t: " << sizeof(uint64_t) << " bytes\n";
}

Kiểu dữ liệu Windows API (thường gặp trong Windows SDK)

Nhóm kiểu số nguyên cơ bản (Windows-style)

Kiểu WindowsTương đương C++Kích thước (bytes)Ghi chú
BYTEunsigned char18-bit không dấu
CHARchar18-bit có dấu
SHORTshort216-bit có dấu
USHORTunsigned short216-bit không dấu
WORDunsigned short2thường dùng trong struct
INTint432-bit có dấu
UINTunsigned int432-bit không dấu
LONGlong4luôn 32-bit (dù 64-bit OS)
ULONGunsigned long4
DWORDunsigned long4"Double Word" (2×16-bit)
BOOLint4Giá trị logic (0 = false, khác 0 = true)
  • Trên Windows 64-bit, LONG vẫn là 4 byte (vì LLP64 model).

Nhóm kiểu địa chỉ/phụ thuộc kiến trúc (Pointer-sized)

Kiểu WindowsKiểu tương đươngKích thước (bytes) (x86/x64)Mục đích
INT_PTRintptr_t4 / 8Số nguyên đủ lớn để chứa con trỏ
UINT_PTRuintptr_t4 / 8unsigned version
LONG_PTRlong/long long4 / 8Như INT_PTR, dùng cho LONG-style
ULONG_PTRunsigned long/ULL4 / 8unsigned version của LONG_PTR
SIZE_Tsize_t4 / 8Kích thước bộ nhớ
SSIZE_Tptrdiff_t4 / 8signed version của SIZE_T
HANDLEvoid*4 / 8Con trỏ trừu tượng (file, mutex,...)
LPVOIDvoid*4 / 8Con trỏ void
LPCVOIDconst void*4 / 8Con trỏ hằng đến dữ liệu bất kỳ
  • Những kiểu này thường dùng trong các hàm WinAPI để hỗ trợ xử lý địa chỉ, pointer, kích thước bộ nhớ trên cả 32-bit và 64-bit.

Nhóm kiểu chuỗi (Windows-style)

Kiểu WindowsTương đương C++Kích thước (bytes) (x86/x64)Mục đích
LPSTRchar*4 / 8Con trỏ đến chuỗi ANSI
LPCSTRconst char*4 / 8Con trỏ hằng đến chuỗi ANSI
LPWSTRwchar_t*4 / 8Con trỏ đến chuỗi Unicode rộng
LPCWSTRconst wchar_t*4 / 8Con trỏ hằng đến chuỗi Unicode rộng

Kiểm tra thực tế:

#include <iostream>
#include <Windows.h>

int main() {
std::cout << "DWORD: " << sizeof(DWORD) << '\n';
std::cout << "LONG_PTR: " << sizeof(LONG_PTR) << '\n';
std::cout << "UINT_PTR: " << sizeof(UINT_PTR) << '\n';
std::cout << "HANDLE: " << sizeof(HANDLE) << '\n';
std::cout << "LPCVOID: " << sizeof(LPCVOID) << " bytes\n";
std::cout << "LPCWSTR: " << sizeof(LPCWSTR) << " bytes\n";

// Ví dụ sử dụng LPCVOID
const char* text = "Test";
LPCVOID buffer = static_cast<LPCVOID>(text);
std::cout << "Buffer data: " << static_cast<const char*>(buffer) << "\n";
}

Ghi chú:

  • Môi trường 32-bit và 64-bit: Sự khác biệt chủ yếu nằm ở kích thước con trỏ và các kiểu liên quan (LPSTR, HANDLE,...). Các kiểu số nguyên (int, long,...) thường giữ nguyên kích thước giữa hai môi trường trên Windows.
  • Windows API: Các kiểu như DWORD, LONG,... được định nghĩa trong <Windows.h> để đảm bảo tính tương thích. Chúng thường ánh xạ đến các kiểu C++ cơ bản.
  • Phụ thuộc trình biên dịch: Một số kiểu như long double có thể khác nhau (ví dụ, trên GCC, long double có thể là 10 hoặc 16 bytes).
  • Unicode vs ANSI: Windows API sử dụng LPWSTR (Unicode) phổ biến hơn LPSTR (ANSI) trong các ứng dụng hiện đại.
  • Best practice:
    • Sử dụng uint32_t thay DWORDconst void* thay LPCVOID trong mã di động để đảm bảo tính tương thích trên nhiều nền tảng.
    • Luôn kiểm tra con trỏ như LPCVOID, HANDLE, hoặc LPWSTR không null trước khi sử dụng.
    • Dùng static_cast khi ép kiểu từ LPCVOID hoặc LPCWSTR để đảm bảo an toàn kiểu.