- Back to Home »
- C »
- C - Storage Classes
Monday, April 27, 2015
Storage Class định nghĩa phạm vi hoạt động cũng như cách mà biến đó hoạt động trong chương trình.
1. auto
2. register
3. static
4. extern
5. volatile
1. auto
auto là một cách khai báo khác của biến thông thường, cách khai báo
int counter
và
auto int counter
là hoàn toàn giống nhau.
2. register
register storage class được dùng để khai báo biến local nằm trên thanh ghi của CPU thay vì trên RAM, mục đích để tăng tốc thực thi các thao tác đối với biến đó, vì thế nó được dùng với các biến được truy xuất rất nhiều lần ví dụ nhử counter chẳng hạn.
register int miles;
Trong thực tế thất rất ít khi găp biến kiểu này.
3. static
Biến static có hai cách dùng, để giới hạn phạm vi của biến trong phạm vi một file source code và duy trì giá trị của biến local khi thoát khỏi một hàm.
Note: Cách dùng static trong C++ tại đây
Cách 1: Giới hạn phạm vi của biến trong phạm vi một file source code
Ví dụ một project có các file source
func.h
#ifndef FUNC_H
#define FUNC_H
#include <stdio.h>
void func_count();
#endif /* FUNC_H */
func.c
#include "func.h"
static int count = 5; /* global variable */
void func_count(){
while(count < 10){
printf("%s: count = %d \n", __FUNCTION__, count) ;
count++;
}
}
main.c
#include <stdio.h>
#include "func.h"
static int count = 5; /* global variable */
int main()
{
while(count--)
{
printf("%s: count = %d \n", __FUNCTION__, count);
}
func_count();
return 0;
}
trong ví dụ trên có hai biến global là count được khai báo ở hai file source là func.c và main.c
vì được khai báo là static nên mặc dù cùng tên nhưng chúng hoàn toàn là hai biến khác nhau.
$ gcc func.c main.c
$ ./a.out
main: count = 4
main: count = 3
main: count = 2
main: count = 1
main: count = 0
func_count: count = 5
func_count: count = 6
func_count: count = 7
func_count: count = 8
func_count: count = 9
Nếu không không khai báo là static thì khi compile sẽ bị lỗi multiple definition
$ gcc func.c main.c
/tmp/ccm9bYEF.o:(.data+0x0): multiple definition of `count'
/tmp/cc9uDZlE.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
Cách 2: Duy trì giá trị của biến local khi đã thực thi xong hàm
Chú ý khi khai báo biến static thì phải có giá trị khởi tạo ban đầu.
main2.c
#include <stdio.h>
/* function declaration */
void func(void);
main()
{
int count = 5;
while(count--)
{
func();
}
return 0;
}
/* function definition */
void func( void )
{
static int i = 5; /* local static variable, must set initial value, is 5 */
int k = 5; /* local variable */
printf("i = %d, k = %d \n", i, k);
i++;
k++;
}
Trong hàm void func(void) có biến local i được khai báo static, trong khi đó k là biến local thường.
$ gcc main2.c
$ ./a.out
i = 5, k = 5
i = 6, k = 5
i = 7, k = 5
i = 8, k = 5
i = 9, k = 5
Kết quả biến i vẫn lưu được giá trị sau mỗi lần gọi hàm.
4. extern
Khác với static nhằm giới hạn phạm vi hoạt động của biến trong một file source code, biến extern nhằm mở rộng phạm vi hoạt động của biến trong nhiều file source code.
func.h
#ifndef FUNC_H
#define FUNC_H
#include <stdio.h>
void func_count();
#endif /* FUNC_H */
func.c
#include "func.h"
extern int count;
void func_count(){
while(count < 10){
printf("%s: count = %d \n", __FUNCTION__, count) ;
count++;
}
}
main.c
#include <stdio.h>
#include "func.h"
int count = 5; /* global variable */
int main()
{
while(count--)
{
printf("%s: count = %d \n", __FUNCTION__, count);
}
func_count();
return 0;
}
Trong ví dụ, biến count được khai báo trong file main.c và được extern trong file func.c
$ gcc func.c main.c
$ ./a.out
main: count = 4
main: count = 3
main: count = 2
main: count = 1
main: count = 0
func_count: count = -1
func_count: count = 0
func_count: count = 1
func_count: count = 2
func_count: count = 3
func_count: count = 4
func_count: count = 5
func_count: count = 6
func_count: count = 7
func_count: count = 8
func_count: count = 9
Kết quả cho thấy count trong func.c cũng chính là count trong main.c được mở rộng ra
Extern cho function: tương tự như ví dụ trên nhưng không có file header func.c để include
func.c
#include <stdio.h>
static int count = 5;
void func_count(){
while(count < 10){
printf("%s: count = %d \n", __FUNCTION__, count) ;
count++;
}
}
main.c
#include <stdio.h>
extern void func_count();
int main()
{
int count = 5;
while(count--)
{
printf("%s: count = %d \n", __FUNCTION__, count);
}
func_count();
return 0;
}
Compile & Execute
$ gcc func.c main.c
$ ./a.out
main: count = 4
main: count = 3
main: count = 2
main: count = 1
main: count = 0
func_count: count = 5
func_count: count = 6
func_count: count = 7
func_count: count = 8
func_count: count = 9
5. volatile
Khi một biến được khai váo với từ khóa volatile thì khi biên dịch compiler sẽ không optimize, biến volatile thường được dùng trong các hàm ngắt và multi thread (sẽ được đề cập ở phần Beginning Linux Programming)
Ví dụ về optimize:
int count;
count = 1;
count = 2;
count = 3;
thì compiler sẽ optimize thành dạng như sau khi biên dịch:
count = 3;
Nếu count được khai báo là volatile
volatile int count;
count = 1;
count = 2;
count = 3;
khi biên dịch compiler vẫn giữ nguyên các thao tác khi chạy chương trình
count = 1;
count = 2;
count = 3;
Tóm lại, khi muốn một biến thực thi tất cả các phép toán trên nó mà không bị optimize thì dùng với kiểu volatile