Kernel linux 개발에 도움되는 라이브러리 정리

Linux Kernel 개발에 도움되는 라이브러리들을 정리하는 글을 쓰게 되었습니다.
" glib.h 라이브러리 "
glib.h 헤더파일은 GLib 라이브러리를 사용하기 위해 필요한 헤더파일이다. GLib은 C 언어를 사용하는 개발자들이 자료구조와 관련된 기능들을 쉽게 구현할 수 있도록 도와주는 라이브러리이다.
Glib.h 헤더파일 안에는 대표적인 자료구조들과 관련된 함수들이 포함되어 있다. 예를들면 ..
1. GArray : 동적 배열을 구현하기 위한 자료구조이다.
#include <glib.h>
GArray* array = g_array_new(FALSE, FALSE, sizeof(int));
' g_array_new '함수는 새로운 ' GArray ' 구조체를 생성하고 초기화하는 함수이다. ' GArray '는 동적으로 크기가 조정되는 배열을 나타내는 구조체이다.
' g_array_new '함수의 파라미터는 다음과 같다.
- ' gboolean zero_terminated ' : 배열의 끝을 알리는 ' NULL '값이 필요한지 여부를 지정한다. 만약 ' TRUE '로 지정하면 배열의 끝에 ' NULL '값이 추가된다.
- ' gboolean clear_ ' : 새로 생성된 배열의 모든 요소를 ' 0 '으로 초기화해야 하는지 여부를 지정한다. 만약 ' TRUE '로 지정하면 배열의 모든 원소를 ' 0 '으로 초기화한다.
- ' guint element_size ' : 배열의 각 원소의 크기를 바이트 단위로 지정한다.
해당 함수의 예시는
GArray *array ;
array = g_array_new (FALSE, FALSE, sizeof(gint)) ;
/*
위 코드는 배열의 끝을 알리는 NULL값을 추가하지 않고, 모든 원소를 0으로 초기화하지 않으며, 각 원소의 크기는 int형 (4바이트)이다.
*/
2. GList : 연결리스트를 구현하기 위한 자료구조이다.
#include <glib.h>
typedef struct{
char *name ;
int age ;
} Person ;
GList *list = NULL ;
Person p1 = { "Earnest", 28 } ;
Person p2 = { "Jennifer", 25 } ;
list = g_list_append( list, &p1 ) ;
list = g_list_append( list, &p2) ;
' g_list_append ' 함수는 GLib 라이브러리에서 제공되는 함수 중 하나로, 연결 리스트의 맨 끝에 새로운 노드를 추가하는 함수이다. 파라미터로는 연결 리스트의 맨 끝에 추가할 노드를 가리키는 포인터와 새로 추가할 노드의 포인터를 전달한다. 함수의 선언은 다음과 같다.
GList *g_list_append(GList *list, gpointer data) ;
- ' list ' : 노드를 추가할 연결 리스트의 맨 끝에 대한 포인터이다.
- ' data ' : 새로 추가할 노드의 데이터이다.
새로운 노드는 ' data ' 매개변수에 저장된 값을 가지며, ' list ' 매개변수가 가리키는 연결 리스트의 맨 끝에 추가된다. 추가된 노드의 포인터가 반환된다.
다음은 ' g_list_append ' 함수를 사용하여 연결 리스트에 새로운 노드를 추가하는 코드를 예시로 들어보겠다.
#include <glib.h>
int main() {
GList *list = NULL ;
list = g_list_append(list, "Earnest") ;
list = g_list_append(list, "Jennifer") ;
list = g_list_append(list, "David") ;
list = g_list_append(list, "Camelot") ;
// list의 모든 node 출력
for (GList *iter = list; iter != NULL; iter = g_list_next(iter)) {
printf("%s\n", (char *)iter->data) ;
}
return 0 ;
}
위의 예시에서는 ' GList ' 포인터 변수 ' list '를 선언하고, ' g_list_append ' 함수를 사용하여 "Earnest", "Jennifer", "David", "Camelot" 네 개의 노드를 연결 리스트에 추가하였다. 그 후에는 ' list '포인터를 사용하여 연결 리스트의 모든 노드를 출력하였다.
3. GHashTable : 해시 테이블을 구현하기 위한 자료구조이다.
#include <glib.h>
GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal) ;
g_hash_table_insert(hash, "name", "Earnest) ;
g_hash_table_insert(hash, "age", "20") ;
우선, 해시 테이블은 키와 값이 쌍으로 이루어진 데이터를 저장하고 검색하기 위한 자료구조이다. 각 키(Key)에 대한 해시값(Hash Value)을 계산하고, 이를 이용하여 해당 키와 값의 쌍을 저장하거나 검색합니다.
GLib 라이브러리에서는 ' GHashTable ' 구조체를 사용하여 해시 테이블을 구현할 수 있다. ' GHashTable ' 구조체는 연결 리스트 방식을 사용하여 해시 테이블을 구현하고, ' g_hash_table_new ' 함수를 사용해서 새로운 ' GHashTable ' 구조체를 생성할 수 있다.
' g_hash_table_new ' 함수의 사용 예시는 다음과 같다.
#include <glib.h>
int main() {
GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal) ;
// 해시 테이블에 데이터 추가
g_hash_table_destory(hash) ;
return 0 ;
}
' g_hash_table_new ' 함수의 첫 번째 매개변수 ' hash_func '는 해시 함수를 지정하는 포인터이다. 이 함수는 해시 테이블에서 각 키에 대한 해시값을 계산하는 역할을 한다. 대부분의 경우 GLib 라이브러리에서 제공하는 해시 함수를 사용하면 된다.
두 번째 매개변수 ' key_equal_func '는 키를 비교하는 함수를 지정하는 포인터이다. 이 함수는 두개의 키를 비교해서 같으면 ' TRUE ', 다르면 ' FALSE '를 반환한다.
' GHashTable ' 구조체를 사용하여 해시 테이블을 구현할 때는 ' g_hash_table_insert ' 함수를 사용하여 데이터를 추가할 수 있다. 다음은 ' g_hash_table_insert ' 함수를 사용해서 간단한 예시를 보이겠다.
#include <glib.h>
int main() {
GHashTable *hash = g_hash_table_new(g_str_hash, g_str_equal) ;
g_hash_table_insert(hash, "name", "Earnest") ;
g_hash_table_insert(hash, "age", "20") ;
// hash table에서 데이터 검색
g_hash_table_destroy(hash) ;
return 0 ;
}
' g_hash_table_insert '함수는 세 개의 매개변수를 받는 것을 볼 수 있다. 첫 번째 매개변수 ' hash_table '는 데이터를 추가할 해시 테이블을 지정한다. 두 번째 매개변수 ' key '는 추가할 데이터의 키를 지정한다. 세 번째 매개변수 ' value '는 추가할 데이터의 값을 지정한다.
' g_hash_table_new ' 함수는 'GHashTable ' 구조체를 생성하고 초기화하여 반환하는 함수이다.
GHashTable *g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func) ;
해당 함수의 선언부이다.
이 함수는 두 개의 매개변수를 받는다. 첫 번째 매개변수인 ' hash_func '는 ' GHashFunc ' 타입으로, 해시 함수 포인터이다. 두 번째 매개변수인 ' key_equal_func '는 ' GEqualFunc ' 타입으로, 두개의 키가 같은지 비교하는 함수 포인터이다. 이 함수는 해시 테이블에 추가될 때, 같은 키가 이미 존재하는지 검사하기 위해 사용된다.
' GHashFunc '와 ' GEqualFunc '는 함수 포인터 타입으로, 정의부는 다음과 같다.
typedef guint (*GHashFunc) (gconstpointer key) ;
typedef gboolean (*GEqualFunc) (gconstpointer a, gconstpoiner b) ;
' GHashFunc ' 함수 포인터는 해시 함수를 정의하는데 사용된다. 이 함수는 해시 테이블에서 사용할 키를 받아 해시값으로 변환해야 하며, 반환값은 ' guint ' 타입이다.
' GEqualFunc ' 함수 포인터는 키를 비교하는데 사용된다. 위에서 말했듯 두개의 키를 받아 같은지 여부를 반환해야 하고, 반환값은 ' gboolean ' 타입이다.
처음으로 돌아가, 다음 예시를 마지막으로, GLIB 라이브러리에 대한 설명을 정리하겠다.
#include <glib.h>
guint hash_func(gconstpointer key) {
return g_str_hash(key) ;
}
gboolean key_equal_func(gconstpointer a, gconstpointer b) {
return g_strcmp0(a, b) == 0 ;
}
int main() {
GHashTable *hash_table = g_hash_table_new(hash_func, key_equal_func) ;
// ...
return 0 ;
}
위 코드는 ' hash_func ' 함수가 ' g_str_hash ' 함수를 호출하여 문자열의 해시값을 계산한다. ' key_equal_func ' 함수는 ' g_strcmp0 ' 함수를 사용하여 두 개의 문자열이 같은지를 판별한다. ' g_hash_table_new ' 함수를 호출할 때 이 두 함수를 인자로 전달하여 ' GHashTable '을 생성한다.
4. GTree : 이진 탐색 트리를 구현하기 위한 자료구조이다.
#include <glib.h>
typedef struct {
char *name ;
int age ;
}Person ;
gint compare_func(gconstpointer a, gconstpointer b, gpointer user_data) {
Person *person1 = (Person*)a ;
Person *person2 = (Person*)b ;
return g_strcmp0(person1->name, person2->name) ;
}
GTree *tree = g_tree_new_full(compare_func, NULL, g_free, NULL) ;
Person *p1 = g_new(Person, 1) ;
p1->name = "Earnest" ;
p1->age = 20 ;
g_tree_insert(tree, p1, NULL) ;
GTree는 GLib 라이브러리에서 제공하는 데이터 구조 중 하나로, 이진 탐색 트리 (binary search tree)로 구현된 자료 구조이다. 이진 탐색 트리는 노드들이 자신보다 작은 값을 가진 노드와 큰 값을가진 노드를 가리키는 구조를 가지고 있어 데이터를 효율적으로 검색하고 정렬할 수 있는 장점이 있다.
GTree 구조체는 키-값 쌍 (key-value pair) 데이터를 저장하는 데 사용된다. 각각의 키와 값은 void 포인터로 캐스팅되어 저장되며, 비교 함수를 사용하여 키 값의 크기를 비교한다.
GTree 구조체는 다음과 같은 함수를 제공한다.
- g_tree_new() : 빈 GTree 구조체를 생성한다.
- g_tree_destory() : GTree 구조체와 연관된 메모리를 해제한다.
- g_tree_insert() : 키-값 쌍을 GTree에 추가한다.
- g_tree_lookup() : 주어진 키에 해당하는 값을 찾아 반환한다.
- g_tree_remove() : 주어진 키에 해당하는 키-값 쌍을 GTree에서 제거한다.
- g_tree_traverse() : GTree의 모든 노드를 순회하며 +(참고)콜백 함수를 호출한다.
+참고
콜백(callback) 함수란, 다른 함수에서 인자로 전달되어 특정 이벤트가 발생했을 때 실행되는 함수를 말한다. 이벤트가 발생하면 해당 함수가 호출되고, 이때 일반적으로 함수를 실행하는 주체는 callback 함수를 호출한 함수가 된다.
콜백 함수는 주로 이벤트 핸들러(event handler), 이벤트 리스너(event listener) 등으로 사용되고 GUI programming에서는 버튼 클릭 등의 사용자 이벤트 처리에도 적용된다. 또한 콜백 함수를 이용하면, 다른 함수에서 사용할 수 있는 유연한 프로그래밍 방식을 제공할 수 있다.
GTree 구조체의 g_tree_traverse() 함수에서 callback 함수는 GTraverseFunc 형태로 정의되어 있다. 이 함수는 GTreeNode 구조체에 대한 포인터와 사용자가 전달한 데이터 포인터를 인자로 받아, 이 둘을 이용하여 트리를 탐색하는 동작을 수행한다. callback 함수에서는 반환값을 가지고, 반환값이 FALSE인 경우 트리의 탐색이 중지된다.
+
' g_tree_traverse() ' 함수는 GTree 구조체에 저장된 모든 노드를 방문하면서 callback function을 호출하는 함수이다. 이때 콜백 함수는
이렇게 GLIB 라이브러리를 사용하면 C 언어에서 자료구조를 구현하고 관리하는 것이 더욱 쉬워질 것으로 보인다.