본문 바로가기
모던 C 언어/C언어 STL

3-1. GLib의 자료구조들 (링크드 리스트 - GList)

by 커널패닉 2021. 12. 17.
반응형
본 포스트를 이해하려면 링크드 리스트에 대한 사전 지식이 필요하다. 만약 링크드 리스트가 무엇인지 모른다면 먼저 해당 내용들에 대해서 구글링을 해 보자.

http://openbooks.sourceforge.net/books/wga/gtk-gnome-intro.html

링크드 리스트는 자료구조책 초반부에 나오면서도 프로그래밍을 하다보면 정말 많이 사용하게 되는 자료구조이다. 개인적으로는 아마 GLib의 모든 자료구조 중에 가장 많이 사용하는 자료구조이다. 백문이불여일견으로 우선 GList로 간단히 데이터 삽입, 삭제, 순회를 하는 예제 코드를 보고, GList를 어떻게 사용하면 되는지 알아보자.

 

#include <glib.h>
#include <stdio.h>

// typedef void* gpointer;

// 리스트를 순회하면서 호출되는 콜백함수
static void print_film(gpointer data, gpointer user_data) {
    char *film = (char*)data;
    int *index = (int*)user_data;
    printf("%dth film: %s\n", (*index)++, film);
}

int main() {
    GList *films = NULL;
    const char *hell = "Hell";
    const char *chachacha = "ChaChaCha";
    const char *evangelion = "Evangelion";
    const char *squid_game = "Squid Game";

    // g_list_append, g_list_prepend로 리스트에 값을 삽입한다, 
    // 이 함수들은 반환값으로 리스트 객체를 반환한다.
    films = g_list_append(films, (gpointer)hell);
    films = g_list_append(films, (gpointer)chachacha);
    films = g_list_append(films, (gpointer)evangelion);
    films = g_list_prepend(films, (gpointer)squid_game);

    unsigned int films_cnt = g_list_length(films);
    char *last_film = g_list_nth_data(films, films_cnt - 1);
    printf("Last film: %s\n", last_film);

    // g_list_remove로 특정 데이터를 삭제한다.
    films = g_list_remove(films, (gpointer)evangelion);
    films_cnt = g_list_length(films);
    last_film = g_list_nth_data(films, films_cnt - 1);
    printf("Last film(modified): %s\n", last_film);

    int index = 0;
    // g_list_foreach 함수로 리스트 내의 값들을 순회한다
    // 콜백 함수를 이용해서 순회된 값을 어떻게 처리할 지 정의할 수 있다.
    g_list_foreach(films, print_film, (gpointer)&index);

    g_list_free(films);

    return 0;
}

결과

$ gcc g_list.c `pkg-config --cflags --libs glib-2.0`
$ ./a.out
Last film: Evangelion
Last film(modified): ChaChaCha
0th film: Squid Game
1th film: Hell
2th film: ChaChaCha

GList는 워낙 간단한 API라 예제코드만 봐도 대략적으로 어떻게 사용하면 되는지 알 수 있을 것이다. 따라서 구구절절하게 API 사용 방법을 설명하는 대신, 여기서는 주의사항 몇 가지를 살펴보도록 하겠다.

 

3.1.1 GList 구조체를 초기화 하기위한 함수가 따로 없음

C 프로그래밍에 익숙하다면 오히려 처음에 헷갈릴 수 있는 내용이다. 대부분의 C 라이브러리들은 처음에 구조체를 초기화하고 사용하기 때문이다. 하나만 예를 들자면 FILE 구조체를 사용하려면 처음에 fopen 함수로 구조체를 초기화 해야한다. 하지만 GList는 별도로 초기화할 필요가 없다. 빈 리스트를 만드는 g_list_alloc() 함수가 있기는 하지만 사용이 필수는 아니다. 바로 g_list_append 등의 함수를 사용하면, 반환값으로 값이 채워진 GList 구조체를 제공한다.

 

3.1.2 반드시 반환값을 GList 구조체에 다시 저장해야 함

반환값을 지정하지 않으면 GList 객체를 받지 못하거나, 받더라도 GList의 리스트의 시작이 HEAD에서 시작하지 않을 수 있다. 따라서 반드시 반환값을 GList 구조체에 다시 저장해야 한다. 반환값을 저장하지 않으면 -Wunused-result gcc 에러가 발생하니 실수를 알아차리기도 쉽다.

 

소개하지 않은 GList의 API들은 공식 문서에 잘 설명되어 있다,

https://docs.gtk.org/glib/struct.List.html

반응형