Về từ khoá static trong ngôn ngữ C
C
29
programming
71
Unix
31
White

Bùi Hồng Hà viết ngày 23/05/2015

Mở đầu

Khi học C cơ bản, chắc hẳn bạn sẽ gặp cách dùng từ khoá static như ví dụ dưới đây:

#include <stdio.h>

void count(int i)
{
    static int num = 0;
    num += i;
    printf("current value of num: %d\n", num);
}

int main()
{
    count(1);
    count(3);
    return 0;
}

Kết quả khi chạy chương trình sẽ là:

current value of num: 1
current value of num: 4

Biến num khai báo static như trên có 2 đặc điểm:

  1. Do được khai báo static nên chỉ được khởi tạo 1 lần duy nhất và tồn tại suốt thời gian chạy của chương trình. Giá trị của biến count sẽ được tích luỹ mỗi khi hàm count được gọi.
  2. Do khai báo trong nội bộ hàm count nên biến chỉ có thể được nhìn thấy bởi các câu lệnh trong hàm count. Nói cách khác, biến nm là 1 biến nội bộ (local variable).

Tuy vậy bạn sẽ bất ngờ khi bắt gặp những cách sử dung static trong như ví dụ dưới đây:

#include <stdio.h>

static int a = 0;

static void count(int i)
{
    static int num = 0;
    num += i;
    printf("current value of num: %d\n", num);
}

int main()
{
    a += 1;
    printf("value of a: %d\n", a);
    count(1);
    count(3);
    return 0;
}

ta bắt gặp static ở 2 nơi nữa:

  1. static trong khai báo hàm
  2. static trong khai báo biến toàn cục

2 từ khoá static này có ngữ nghĩa như thế nào?

Để hiểu được ngữ nghĩa mới của static này, ta cần hiểu 1 khái niệm: đơn vị biên dịch (translation unit).

Mỗi project thường được viết trên nhiều file (vì mục đích phân chia module, đảm bảo tính dễ bảo trì). Mỗi file.c trong dự án sẽ là 1 đơn vị biên dịch. Quá trình biên dịch 1 project C sẽ là: biên dịch các đơn vị độc lập .c ra các object file *.o (.obj) và liên kết (link) các đơn vị object file thành chương trình.

Mỗi đơn vị sẽ có các thủ tục (procedure) hoặc function riêng. Code ở 1 đơn vị biên dịch có thể sử dụng thủ tục hoặc hàm, hay cả biến toàn cục ở đơn vị biên dịch khác. Ví dụ:

//-----------------------
//A.c

int avar;

void a() {};

void b() {};

// -----------------------
//C.c

extern int avar;

void c() {};

void d() {};

thì trong a() của A.c ta có thể gọi c() một cách thoải mái. Biến avar sẽ được sử dụng cả ở A.c và C.c (biến toàn cục thực thụ!)

Để hạn chế việc sử dụng này (tránh va đụng tên hàm giữa các đơn vị biên dịch), người ta đưa khái niệm hàm tĩnh (static function) và biến tĩnh (static global variable).

Ngữ nghĩa:

  • Biến toàn cục tĩnh sẽ có phạm vi trên đơn vị biên dịch. Điều đó có nghĩa là đơn vị khác không có cách nào truy cập được biến này.
  • Hàm tĩnh sẽ có phạm vi trên đơn vị biên dịch. Điều đó có nghĩa đơn vị khác không thể truy cập được hàm này.

Do đó

//-----------------
//A.c

static int avar;

static void a() {};

void b() {};

//------------------
//C.c

extern int avar;

void c() {};

void d() {};

Nếu ta khai báo static như trên, các hàm c, d trong C.c sẽ không thể nào truy cập được hàm a cũng như biến avar (dù rằng avar được khai báo extern trong C.c).

Tóm lược

static có 2 ngữ nghĩa:

  • Khi được sử dụng trong phạm vi toàn cục của 1 đơn vị biên dịch, static hạn chế truy cập từ các đơn vị biên dịch khác (áp dụng với cả hàm và biến toàn cục).
  • Khi được sự dụng trong phạm vi cục bộ của 1 thủ tục hay hàm, static có nghĩa là biến được khai báo tồn tại trong suốt thời gian chạy của chương trình và chỉ được khởi tạo 1 lần duy nhất.
Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Bùi Hồng Hà

59 bài viết.
286 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
75 8
Bài viết tổng hợp cơ chế hoạt động của https Chút ít về chữ ký điện tử Chữ ký điện tử là cơ chế bao gồm 3 thuật toán: Thuật toán chọn một khóa...
Bùi Hồng Hà viết 3 năm trước
75 8
White
44 7
Giới thiệu Gần đây thấy bản thân chém gió rất nhiều về MapReduce, Hadoop v.v nhưng chưa thấy có bài viết nào tổng hợp + giải thích cụ thể về MapRe...
Bùi Hồng Hà viết hơn 2 năm trước
44 7
White
35 1
Giới thiệu Google là một công ty dẫn đầu về phần mềm xử lý Big Data. Hầu hết các phần mềm xử lý dữ liệu như Hadoop đều có nguồn gốc ý tưởng từ Goo...
Bùi Hồng Hà viết hơn 2 năm trước
35 1
Bài viết liên quan
White
3 1
Chú ý: Bài viết này trình bày chủ yếu cho CentOS 64 bit, tuy nhiên ý tưởng có thể áp dụng cho các hệ điều hành khác. Cuối bài có ghi chú cho Ubunt...
Ngoc Dao viết hơn 2 năm trước
3 1
White
18 5
Gần đây tôi có dịp đụng vào CMake, nên có tìm hiểu một chút về nó. Hy vọng có ích cho anh em. Nó cung cấp tính năng sinh ra Makefile một cách hiệu...
Phùng Văn Tú viết gần 3 năm trước
18 5
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
59 bài viết.
286 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!