C là ngôn ngữ tĩnh phạm vi (static scoping / lexical scoping). Phạm vi của biến được xác định bởi vị trí khai báo trong mã nguồn, không phụ thuộc vào luồng gọi hàm tại runtime.
Các loại phạm vi trong C
| Loại | Phạm vi | Thời gian sống | Ví dụ |
|---|---|---|---|
| File scope (Global) | Toàn file từ chỗ khai báo | Chương trình | int x; ngoài hàm |
| Block scope (Local) | Trong cặp { } chứa nó | Vào block đến ra block | int x; trong hàm |
| Function prototype scope | Chỉ trong prototype | Chỉ prototype | void f(int x); |
| Function scope | Toàn hàm (chỉ label) | Hàm | goto label; |
Ví dụ minh họa Static Scope
#include <stdio.h>
int x = 0; // Global
int my_function() {
return x; // Luôn trả về global x
}
int my_function2() {
int x = 1; // Local x che khuất global x
return my_function(); // Gọi my_function
}
int main() {
printf("Gia tri: %d\n", my_function2());
}
Kết quả
Gia tri: 0
Giải thích
my_function luôn truy xuất x ở phạm vi file (global = 0), không bị ảnh hưởng bởi biến cục bộ x = 1 trong my_function2. Đây là bản chất của static scoping: phân giải tên biến dựa trên cấu trúc lồng nhau của code, không phải call stack.
So sánh: Static Scope vs Dynamic Scope
| Đặc điểm | Static Scope (C, C++, Java, Python...) | Dynamic Scope (Lisp cũ, Bash, Perl local) |
|---|---|---|
| Quy tắc tìm biến | Dựa trên vị trí viết code (lexical) | Dựa trên call stack runtime |
| Ví dụ trên | Trả về 0 (global) | Sẽ trả về 1 (local của caller) |
| Có thể phân tích tĩnh | Có | Khó |
| Module/namespace | Hỗ trợ tốt | Khó quản lý |
Shadowing (Che khuất)
int x = 10; // Global
void func() {
int x = 20; // Shadow global x
{
int x = 30; // Shadow local x
printf("%d\n", x); // 30
}
printf("%d\n", x); // 20
}
Static local variable
void counter() {
static int count = 0; // Khởi tạo 1 lần, giữ giá trị giữa các lần gọi
printf("%d ", ++count);
}
int main() {
counter(); // 1
counter(); // 2
counter(); // 3
}
Tóm tắt
- C dùng static/lexical scoping
- Biến global: Phạm vi file, lifetime chương trình
- Biến local: Phạm vi block, lifetime lần gọi hàm
- Biến static local: Phạm vi block, lifetime chương trình
- Shadowing: Biến trong scope con che biến scope cha
- Không phụ thuộc call stack (khác dynamic scope)