- vừa được xem lúc

Tại sao cần phải ép kiểu con trỏ

0 0 3

Người đăng: Nguyễn Đặng Triều

Theo Viblo Asia

Trả lời

Ép kiểu con trỏ cho phép ta:

  • Đọc một vùng nhớ theo kiểu khác.
  • Truy cập phần cứng đúng với kiểu dữ liệu
  • ...

Một số ví dụ để bạn có thể hình dung được lỗi xảy ra khi sử dụng con trỏ sai kiểu dữ liệu

Ví dụ 1

#include <stdio.h>
#include <stdint.h> int main()
{ uint8_t *p; int arr[3] = {1, 2, 3}; p = arr; // in ra màn hình các phần tử của mảng for(int i = 0; i < 3; i++) { printf("arr[%d] = %d\n", i, *(p++)); } return 0;
}

Ouput

arr[0] = 1
arr[1] = 0
arr[2] = 0

Chà! Kết quả ở đây là không mong muốn rồi, arr[1] = 2, arr[2] = 3 thì mới chính xác. Vậy lí do ở đây là gì ?

  • Nếu để ý kỹ bạn sẽ thấy, kiểu dữ liệu của con trỏ là uint8_t (một kiểu dữ liệu 8bit).
  • Lúc này nếu ta sử dụng các phép toàn cho con trỏ, p++ hay p--,... nó sẽ tăng địa chỉ tương ứng với kích thước của con trỏ. image.png Note: kiểu dữ liệu được sắp xếp theo thiểu little-endian.

uint8_t *p thì mỗi lần p++ sẽ tăng địa chỉ tương ứng 1 byte. Nếu bây giờ ta tiếp tục tăng con trỏ, tới lúc nào đó nó sẽ trỏ tới số 2.

printf("%d\n", *(p++));
printf("%d\n", *(p++));

Thêm 2 đoạn mã này, vào code trên thì ta sẽ được:

arr[0] = 1
arr[1] = 0
arr[2] = 0
0
2 // Đây chính là giá trị phần tử của 2.

Thay vì màu mè như trên bây giờ, ta chỉ việc ép kiểu con trỏ lại thành kiểu int thì mọi thứ sẽ hoạt động đúng.

#include <stdio.h>
#include <stdint.h> int main()
{ uint8_t *p; int arr[3] = {1, 2, 3}; p = arr; // in ra màn hình các phần tử của mảng for(int i = 0; i < 3; i++) { printf("arr[%d] = %d\n", i, *((int *)p)); p += sizeof(int); // cần phải tăng đúng kích thước của kiểu dữ liệu. } return 0;
}

Ouput

arr[0] = 1
arr[1] = 2
arr[2] = 3

image.png

Đây chỉ là ví dụ đơn giản để mô phỏng lại lỗi xảy ra trong thực tế nếu bạn không ép kiểu chính xác của con trỏ khi xử lí.

Ví dụ 2

Đọc dữ liệu từ việc căng chỉnh con trỏ.

Có một biến data nắm giữ các số từ 1 -> 4. In các số này ra màn hình
#include <stdio.h>
#include <stdint.h> int main()
{ unsigned int data = 16909060; int *p; p = &data; for(int i = 0; i < 4; i++) { printf("%d\n", *(p++)); }
}

Ouput

16909060
1
-1925391180
32765

Đây là kết quả mà ta không mong đợi.

Điều này xảy ra là do ta đã tăng địa chỉ của con trỏ theo kích thước int - 4 byte trong 1 lần. Trong khi dữ liệu lại được lưu trữ liên tiếp nhau. image.png

Bây giờ ta cần chính sửa con trỏ lại theo kiểu uint8_t.

#include <stdio.h>
#include <stdint.h> int main()
{ unsigned int data = 16909060; // 0x01020304 uint8_t *p; p = &data; for(int i = 0; i < 4; i++) { printf("%d\n", *(p++)); } }

Output

4
3
2
1

Tại vì sao nó lại hiện 1 -> 4 mà không phải là 4 -> 1. Hãy phản hồi bên dưới bài viết.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Memory layout của một chương trình C/C++

1. Đặt Vấn Đề.

0 0 58

- vừa được xem lúc

Sự khác nhau giữa bộ nhớ Heap và bộ nhớ Stack trong lập trình

1. Giới thiệu. . Như chúng ta đã biết thì việc Quản lý bộ nhớ đối với một lập trình viên là rất quan trọng.

0 0 72

- vừa được xem lúc

Tích hợp thư viện C/C++ vào một dự án Flutter như thế nào?

Chào các bạn hôm nay rảnh rỗi thì mình viết một bài hướng dẫn về cách tích hợp một thư viện C/C++ vào một dự án Flutter. Thì cũng khá đơn giãn thôi vì Flutter đã cũng cấp cho chúng ta một thư viện khá

0 0 76

- vừa được xem lúc

Programming

Definition of Programming. .

0 0 50

- vừa được xem lúc

Gọi hàm của C++ trong Python bằng ctypes

Nếu đã từng dùng qua các thư viện liên quan đến toán học của Python như numpy, các bạn sẽ để ý thấy các nó có tốc độ xử lý rất nhanh. Điều này là do một phần của package này được viết bằng C/C++ và ph

0 0 51

- vừa được xem lúc

Build ứng dụng Cross Platform với Go và CGO

1. Giới thiệu.

0 0 52