Trong những bài viết trước, bạn đã biết rằng, giá trị của một biến được chứa trong dãy các bits. Và kiểu dữ liệu của biến đó báo cho trình biên dịch cách làm thế dào để chuyển những giá trị bits đó thành giá trị của biến.Tuy nhiên, có một số trường hợp thì dữ liệu cần chuyển từ một loại này sang một loại khác cho phù hợp với kiểu dữ liệu mà bạn khai báo. Mình sẽ gọi việc làm này là ép kiểu (type conversion).

Implicit type conversion (ép kiểu ẩn) là việc làm hoàn toàn tự động của trình biên dịch khi giá trị mà bạn gán cho biến khác kiểu với kiểu dữ liệu của biến. Khi một giá trị khác loại được gán cho một biến khác loại, trình biên dịch sẽ tự động chuyển giá trị đem gán thành một kiểu dữ liệu mới để gán cho biến.

Ví dụ:


double dValue = 3; // Trình biên dịch tự động chuyển dValue thành 3.0
int nValue = 3.14156; // Trình biên dịch tự động chuyển nValue = 3

Trong ví dụ thứ nhất, giá trị 3 sẽ được chuyển thành giá trị double và sau đó gán vào dValue. Trình biên dịch sẽ không cảnh báo về việc làm này. Một vài loại ép kiểu vốn đã không an toàn, và nếu trình biên dịch có thể nhận thấy được sự không an toàn từ việc ép kiểu, nó sẽ đưa ra một cảnh báo.

Trong ví dụ thứ 2, phần số thực của số kiểu double (trong trường hợp này là 3.14156) sẽ bị bỏ đi bởi vì kiểu dữ liệu integer không có phần thực. Vì vậy khi chuyển một số từ kiểu double sang kiểu int thường dẩn đến việc mất dữ liệu. Trình biên dịch sẽ đưa ra một cảnh báo về vấn đề này. Những trường hợp khác khi chuyển đổi kiểu dữ liệu có thể không an toàn nữa là gán một số không dấu cho một biến có dấu. Và gán một biến có giá trị lớn (long-4byte) cho một biến thuộc kiểu dữ liệu nhỏ (short-2 bytes).

Khi tôi thử khai báo câu lệnh int nValue = 3.14156; trong chương trình, thì trình biên biên dịch cảnh báo lỗi.

Khi tính toán biểu thức, trình biên dịch chia mỗi biểu thức thành nhiều biểu thức con. Thường thì mỗi biểu thức con bao gồm toán tử unary(++) hoặc toán tử binary (+,-,*,/) và một vài toán hạng. Hầu hết toán tử binary yêu cầu những toán tử của chúng cùng loại. Nếu toán tử gồm nhiều loại khác nhau thì trình biên dịch sẽ chuyển một toán tử cho phù hợp với toán tử khác. Để làm điều này, trình biên dịch sử dụng bảng cấp độ của loại dữ liệu (heirarchy):

Long double (highest)
Double
Float
Unsigned long int
Long int
Unsigned int
Int (lowest)

Ví dụ: Trong biểu thức 2 + 3.14159 , toán tử + yêu cầu các toán hạng phải cùng loại với nhau. Trong trường hợp này, vế trái của toán tử cộng là kiểu số nguyên, và vế phải của toán tử cộng là kiểu double. Bởi vì double có thứ hạng cao hơn trong hierarchy. Kiểu int sẽ được chuyển đổi thành kiểu double. Lúc này biểu thức sẻ tính toán như 2.0 + 3.14159, và kết quả là 5.14159

Có một câu hỏi đặt ra là, tại sao kiểu integer lại ở cuối cùng trong hierarchy. Còn các kiểu char và short thì sao ?. Char và short thì luôn luôn được thăng cấp ngầm lên kiểu integer (hoặc unsigned interger (số nguyên ko dấu)) trước khi tính toán. Điều này gọi là “widening”.

Khi mới học lập trình, tôi đã có lần viết cậu lênh như dưới đây:

Float fValue = 10/4;

Tuy nhiên bởi vì cả 10 và 4 đều là kiểu integer, chúng sẽ không được thăng cấp lên kiểu float tại thời điểm này. Chúng sẽ thực hiên phép chia 10/4 và kết quả mà bạn nhận được là 2. Sau đó nó chuyển đổi sang giá trị 2.0 và gán lại cho fValue.

Trong trường hợp ở trên bạn sử dụng giá trị cho phép chia (chứ ko phải sử dụng biến), Nếu bạn thay thế một trong hai số nguyên đó thành kiểu số thực (10.0 hoặc 4.0), thì trình biên dịch sẽ chuyển cả 2 số đó thành số thực và phép chia sẻ cho ra một số thuộc kiểu số thực, vì vậy bạn sẽ không mất dữ liệu.

Nhưng điều gì sẽ xảy ra nếu bạn sử dụng biến trong trường hợp này.

int nValue1 = 10;
int nValue2 = 4;
float fValue = nValue1 / nValue2;

fValue sẻ nhận được kết quả cuối cùng là 2.0. Vậy phải làm thế nào để báo cho trình biên dịch biết bạn muốn sử dụng phép chia số thực thay vì phép chia số nguyên? Câu trả lời là sử dụng cast

Casting

Casting là cách chuyển đổi kiểu dữ liệu theo mong muốn của lập trình viên. Trong chương trình C chuẩn, Cast được thực hiện thông qua toán tử (), với tên của loại dữ liệu muốn cast ở bên trong.

Ví dụ:


int nValue1 = 10;
int nValue2 = 4;
float fValue = (float)nValue1 / nValue2;

Trong chương trình ở trên, chúng ta sử dụng float cast để báo cho trình biên dịch biết để thăng cấp nValue1 thành kiểu float. Bởi vì nValue1 có kiểu float nên nValue2 sau đó cũng được chuyển đổi thành kiểu float. Và khi đó, phép chia là phép chia kiểu số thực(float) thay vì số nguyên (integer)

C++ cũng sẽ cho bạn sử dụng kiểu C cast này trong chương trình C++ của bạn:


int nValue1 = 10;
int nValue2 = 4;
float fValue = (float)nValue1 / nValue2;

C++ giới thiệu một toán tử casting mới gọi là static_cast. Static cast làm việc tương tự như kiểu C cast.

int nValue1 = 10;
int nValue2 = 4;
float fValue = static_cast(nValue1) / nValue2;

Bạn nên tránh sử dụng casting trong tất cả mọi trường hợp nếu có thể, bởi vì bất kì ở đâu sử dụng cast, ở đó có thể là nguyên nhân gây ra nhiều vấn đề cho chương trình của bạn. Nhưng đôi khi bạn bắt buộc phải sử dụng nếu không thể tránh được. Trong trường hợp này, trong C++ bạn nên sử dụng static_cast thay vì S-style cast

Đăng nhận xét Blogger

Để hạn chế spam blog, bình luận của bạn sẽ được đăng sau khi admin xét duyệt! Mong bạn thông cảm :)

 
Top