Typedef cho phép lập trình viên tạo bí danh(alias) cho một kiểu dữ liệu và sử dụng tên bí danh thay vì tên kiểu thực. Typedef nghĩa đen là viết tắt của, “định nghĩa kiểu”.

Để khai báo typedef, chỉ cần sử dụng từ khóa typedef, theo sau là loại cho bí danh, theo sau là tên bí danh:

typedef double distance_t; // define distance_t as an alias for type double
 
// The following two statements are equivalent:
double howFar;
distance_t howFar;

Theo quy ước, tên typedef được khai báo bằng hậu tố “_t”. Điều này giúp chỉ ra rằng số nhận dạng đại diện cho một kiểu chứ không phải một biến hoặc hàm và cũng giúp ngăn chặn xung đột đặt tên với các số nhận dạng khác.

Lưu ý rằng một typedef không khai báo một kiểu mới. Đúng hơn, nó chỉ đơn giản là một bí danh (tên khác) cho một kiểu hiện có. Typedef có thể được sử dụng thay thế cho nhau ở bất cứ đâu mà một loại thông thường có thể được sử dụng.

Mặc dù điều sau không có ý nghĩa về mặt ngữ nghĩa, nhưng nó là C ++ hợp lệ:

/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact: cafedevn@gmail.com
Fanpage: https://www.facebook.com/cafedevn
Group: https://www.facebook.com/groups/cafedev.vn/
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
Pinterest: https://www.pinterest.com/cafedevvn/
YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
*/

int main()
{
    typedef long miles_t;
    typedef long speed_t;
 
    miles_t distance { 5 };
    speed_t mhz  { 3200 };
 
    // The following is valid, because distance and mhz are both actually type long
    distance = mhz;
 
    return 0;
}

typedef và bí danh kiểu tuân theo các quy tắc xác định phạm vi giống như các biến. Typedefs mile_t và speed_t chỉ có thể sử dụng được trong hàm main (). Nếu chúng được đặt trong một hàm khác, main () sẽ không thể truy cập chúng. Nếu chúng được đặt bên ngoài main (), trong phạm vi toàn cục, tất cả các hàm sẽ có thể truy cập chúng.

Tuy nhiên, typedefs có một số vấn đề. Đầu tiên, bạn rất dễ quên việc định nghĩa kiểu hay tên loại có trước hay không. Câu nào đúng?

typedef distance_t double; // incorrect
typedef double distance_t; // correct

Tôi không bao giờ có thể nhớ được.

Thứ hai, cú pháp của typedefs trở nên xấu hơn với nhiều kiểu phức tạp hơn, đặc biệt là con trỏ hàm (chúng ta sẽ đề cập đến trong bài học – Con trỏ hàm):

1. Kiểu bí danh

Để giúp giải quyết những vấn đề này, một cú pháp cải tiến cho typedefs đã được giới thiệu để bắt chước cách khai báo các biến. Cú pháp này được gọi là bí danh kiểu.

Cho typedef sau:

typedef double distance_t; // define distance_t as an alias for type double

Điều này có thể được khai báo dưới dạng bí danh loại sau:

using distance_t = double; // define distance_t as an alias for type double

Cả hai tương đương về chức năng.

Lưu ý rằng mặc dù cú pháp kiểu bí danh sử dụng từ khóa “using”, nhưng đây là một ý nghĩa quá tải và không liên quan gì đến các câu lệnh using liên quan đến không gian tên. Do đó, nó không bị ảnh hưởng bởi quy tắc không sử dụng “sử dụng không gian tên”.

Cú pháp bí danh kiểu này rõ ràng hơn cho các trường hợp định dạng kiểu nâng cao hơn và nên được ưu tiên hơn.

2. Sử dụng bí danh loại để dễ đọc

Một cách sử dụng cho các bí danh loại là trợ giúp về tài liệu và tính dễ đọc. Các tên kiểu dữ liệu như char, int, long, double và bool rất tốt để mô tả kiểu mà hàm trả về, nhưng chúng ta thường muốn biết mục đích của giá trị trả về là gì.

Ví dụ, hãy xem xét chức năng sau:

int GradeTest();

Chúng ta có thể thấy rằng giá trị trả về là một số nguyên, nhưng số nguyên có nghĩa là gì? Một điểm thư? Số lượng câu hỏi bị trượt? Số ID của sinh viên? Một code lỗi? Ai biết! Int không cho chúng ta biết bất cứ điều gì.

using testScore_t = int;
testScore_t GradeTest();

Tuy nhiên, việc sử dụng kiểu trả về testScore_t làm cho nó rõ ràng là hàm đang trả về kiểu đại diện cho điểm kiểm tra.

3. Sử dụng bí danh loại để bảo trì code dễ dàng hơn

Loại bí danh cũng cho phép bạn thay đổi kiểu cơ bản của một đối tượng mà không cần phải thay đổi nhiều code. Ví dụ: nếu bạn đang sử dụng code ngắn để giữ số ID của sinh viên, nhưng sau đó bạn quyết định cần code dài để thay thế, bạn sẽ phải xem qua nhiều code và thay thế ngắn bằng dài. Có lẽ sẽ rất khó để tìm ra chiếc quần đùi nào đang được sử dụng để giữ số ID và chiếc quần nào đang được sử dụng cho các mục đích khác.

Tuy nhiên, với bí danh kiểu, tất cả những gì bạn phải làm là thay đổi bằng cách sử dụng studentID_t = short; để sử dụng studentID_t = long ;. Tuy nhiên, vẫn cần thận trọng khi thay đổi kiểu bí danh kiểu thành một kiểu trong họ kiểu khác (ví dụ: số nguyên thành giá trị dấu phẩy động hoặc ngược lại)! Loại mới có thể có vấn đề so sánh hoặc phân chia số nguyên / dấu phẩy động hoặc các vấn đề khác mà loại cũ không có.

4. Sử dụng kiểu bí danh để code hóa nền tảng độc lập

Một ưu điểm khác của bí danh kiểu là chúng có thể được sử dụng để ẩn các chi tiết cụ thể của nền tảng. Trên một số nền tảng, giá trị int là 2 byte và trên các nền tảng khác, nó là 4 byte. Do đó, việc sử dụng int để lưu trữ hơn 2 byte thông tin có thể tiềm ẩn nguy hiểm khi viết code độc lập nền tảng.

Bởi vì char, short, int và long không cho biết kích thước của chúng, nên các chương trình đa nền tảng khá phổ biến sử dụng bí danh kiểu để xác định bí danh bao gồm kích thước của kiểu tính bằng bit. Ví dụ: int8_t sẽ là số nguyên có dấu 8 bit, int16_t là số nguyên có dấu 16 bit và int32_t là số nguyên có dấu 32 bit. Sử dụng bí danh kiểu theo cách này giúp ngăn ngừa sai lầm và làm rõ ràng hơn về loại giả định đã được thực hiện về kích thước của biến.

Để đảm bảo mỗi loại bí danh phân giải thành loại có kích thước phù hợp, loại bí danh thuộc loại này thường được sử dụng cùng với các chỉ thị tiền xử lý:

#ifdef INT_2_BYTES
using int8_t = char;
using int16_t = int;
using int32_t = long;
#else
using int8_t = char;
using int16_t = short;
using int32_t = int;
#endif

Trên các máy mà số nguyên chỉ có 2 byte, INT_2_BYTES có thể được # define và chương trình sẽ được biên dịch với tập hợp các bí danh loại hàng đầu. Trên các máy có số nguyên là 4 byte, việc không xác định INT_2_BYTES sẽ làm cho tập hợp bí danh loại dưới cùng được sử dụng. Theo cách này, int8_t sẽ giải quyết thành số nguyên 1 byte, int16_t sẽ phân giải thành số nguyên 2 byte và int32_t sẽ phân giải thành số nguyên 4 byte bằng cách sử dụng kết hợp char, short, int và long phù hợp với máy tính chương trình đang được biên dịch trên.

Đây chính xác là cách các số nguyên có chiều rộng cố định, như std :: int8_t (được trình bày trong bài – Số nguyên có chiều rộng cố định và size_t, được định nghĩa!

Đây cũng là lý do mà vấn đề với int8_t được coi là một char xuất phát – std :: int8_t là một bí danh kiểu của char, và do đó chỉ là một bí danh cho một char chứ không phải là một kiểu duy nhất. Kết quả là:

#include <cstdint> // for fixed-width integers
#include <iostream>
 
int main()
{
    std::int8_t i{ 97 }; // int8_t is actually a type alias for signed char
    std::cout << i;
 
    return 0;
}

Chương trình này in:

a

không phải 97, vì std :: cout in char dưới dạng ký tự ASCII, không phải số.

5. Sử dụng bí danh kiểu để làm cho các kiểu phức tạp trở nên đơn giản

Mặc dù cho đến nay chúng ta mới chỉ xử lý các kiểu dữ liệu đơn giản nhưng trong C ++ nâng cao, bạn có thể thấy một biến và hàm được khai báo như thế này:

std::vector<std::pair<std::string, int> > pairlist;
 
bool hasDuplicates(std::vector<std::pair<std::string, int> > pairlist)
{
    // some code here
}

Nhập std :: vector <std :: pair <std :: string, int>> ở mọi nơi bạn cần sử dụng kiểu đó có thể trở nên rườm rà. Sẽ dễ dàng hơn nhiều khi sử dụng bí danh loại:

using pairlist_t = std::vector<std::pair<std::string, int> >; // make pairlist_t an alias for this crazy type
 
pairlist_t pairlist; // instantiate a pairlist_t variable
 
bool hasDuplicates(pairlist_t pairlist) // use pairlist_t in a function parameter
{
    // some code here
}

Tốt hơn nhiều! Bây giờ chúng ta chỉ phải gõ “pairlist_t” thay vì std :: vector <std :: pair <std :: string, int>>.

Đừng lo lắng nếu bạn chưa biết std :: vector, std :: pair hoặc tất cả các dấu ngoặc nhọn điên rồ này là gì. Điều duy nhất bạn thực sự cần hiểu ở đây là các bí danh kiểu cho phép bạn lấy các kiểu phức tạp và đặt cho chúng một cái tên đơn giản, điều này làm cho các kiểu đó dễ làm việc và hiểu hơn.

Bạn nên

Ưu tiên kiểu bí danh hơn typedef và sử dụng chúng một cách tự do để ghi lại ý nghĩa của các kiểu dữ liệu của bạn.

Cài ứng dụng cafedev để dễ dàng cập nhật tin và học lập trình mọi lúc mọi nơi tại đây.

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!