🌱 Các lớp lưu trữ trong C - Storage Class
Lớp lưu trữ (Storage Class) định nghĩa phạm vi (Scope) và vòng đời (Life-time) của biến và/hoặc các hàm bên trong một chương trình, thường đứng trước kiểu dữ liệu mà chúng tác động.
Trong C chúng ta có 4 kiểu lớp lưu trữ như sau:
👉 Lớp lưu trữ Auto
Đây là lớp lưu trữ mặc định cho tất cả các biến trong C. Và vị trí cũng như phạm vi thực hiện của các biến này sẽ phụ thuộc vào Scope - vị trí của các biến đó trong chương trình. Về cơ bản một biến sẽ có 2 scope:
- Local - Các biến được khai báo bên trong các hàm. Các biến Local Auto sẽ được khởi tạo trên stack khi gọi hàm và chỉ tồn tại bên trong hàm.
Khi kết thúc hàm, biến sẽ bị pop ra khỏi bộ nhớ stack ➔ Tức là chỗ ô nhớ đó vẫn giữ giá trị của biến, những Stack Pointer đã bị thay đổi, và biến đó không thể truy cập bằng chương trình nữa.
Chính vì vậy, các biến local khi không được khởi tạo giá trị, nó sẽ lấy một giá trị nào đó trên bộ nhớ Stack, mà chúng ta thường gọi là giá trị "rác" - garbage value. - Global - Các biến được khai báo bên ngoài tất cả các hàm. Biến Global Auto sẽ được khởi tạo khi bắt đầu chương trình trên vùng nhớ .data (với các biến được khởi tạo giá trị)/.bss (các biến không được khởi tạo giá trị), và tồn tại trong suốt thời gian hoạt động của chương trình.
Cũng như các biến này sẽ được sử dụng trong tất cả các hàm của chương trình, và có thể được sử dụng chung cho tất cả các file bằng từ khóa Extern (sẽ nhắc đến bên dưới).
#include <stdio.h>
int func(int i)
{
int num;
num += i;
printf("%d ", num);
}
int main()
{
func(1);
func(2);
return 0;
}
Run This Code
- Dễ thấy lần gọi hàm func(1) đầu tiên, i = 1, num là một biến local (chưa được khởi tạo) nên giá trị của nó lấy trên stack, num = 0 là do chạy lần đầu thì vùng nhớ đó giá trị reset là 0, còn giá trị rác là do trước đó có chương trình khác dùng vùng stack đó rồi - Ở đây mình giả sử num = 0 trong lần đầu tiên này.
- num += i thì num = 1 ➔ in ra 1. Thoát khỏi hàm, lúc này cái vị trị do ông num bỏ lại có giá trị là 1, chỉ là stack pointer thay đổi thôi!
- Lần gọi hàm thứ 2 - func(2) , lúc này num vẫn lấy giá trị ngẫu nhiên trên stack, nhưng mà giá trị ngẫu nhiên đó lại đúng vị trí lúc nãy, và đang bằng 1! ➔ num = 1, i tất nhiên được gán bằng 2.
- num += i thì num = 3 ➔ in ra 3.
👉 Lớp lưu trữ Register
Dùng để định nghĩa các biến mà nên được lưu giữ trong một thanh ghi (của CPU) thay vì RAM.
=> biến có kích cỡ tối đa bằng với kích cỡ thanh ghi (tức là nếu biến char và thanh ghi 32-bits thì tự động biến này sẽ mang kích cỡ 32-bits nếu được đặt trên thanh ghi) và không thể truy xuất tới địa chỉ của biến này (vì không có địa chỉ bộ nhớ).
Thường dùng cho các biến yêu cầu truy cập nhanh như các biến đếm và chỉ sử dụng trong những trường hợp thực sự cần thiết (Mình từng gặp khi đọc phần code khi xây dựng hệ điều hành).
register int count;
Đôi khi một số trường hợp, compiler có thể optimize một số biến local thành register variable để tăng tốc độ.
👉 Lớp lưu trữ Static
Giống như global variable, các biến static (cả local hay global) đều sẽ được phân bổ lên vùng nhớ .data/.bss.
Từ khóa "static" dùng để nói cho compiler biết phải giữ một biến local tồn tại trong toàn bộ thời gian sống của chương trình thay vì tạo và hủy biến mỗi lần nó vào và ra khỏi phạm vi biến. Giống với global variable, biến static local nếu không được khởi tạo giá trị sẽ được gán giá trị là 0 (vì nó nằm trên .bss).
Đối với biến global, nó cho biết biến có giới hạn trong tập tin mà nó được khai báo.
=> Các biến static cho phép nó duy trì giá trị giữa các lần gọi hàm.
👉 Lớp lưu trữ Extern
Được dùng phổ biến khi có hai hoặc nhiều file chia sẻ cùng biến global hay hàm global. (Chẳng hạn có 1 biến đếm mà muốn nó đếm cả trong file khác thì cần dùng extern).
Biến extern chỉ được khai báo và khởi tạo 1 lần tại 1 file, và những file khác muốn dùng nó thì cần thêm từ khóa extern ở trước :)))
>>>= Follow ngay =<<<
💚 Kênh Youtube Lập trình - Điện tử 💚
Để nhận được những bài học miễn phí mới nhất nhé 😊