[C] Cello 라이브러리 in Windows

[원본 링크]

http://libcello.org/home

순수 C 기반으로 일반화, 함수 다형성, 예외 시스템, 가비지콜렉션, 생성자/소멸자, 인터페이스 등을 구현한 라이브러리라고 한다.
도대체 어떻게 했는지는 모르겠지만 그렇다고 한다.
보니까 스마트 포인터도 있다.

참고로 이건 gcc/C99 이후 환경에서만 작동하는듯하다.
msvs-c에서는 동작하지 않는다.

윈도에서 쓰기도 좀 불편하다. 기본적으로 리눅스를 타겟으로 잡은듯하다.
라이브러리를 빌드해서 써야하는데...
윈도판 make까지 깔아서 makefile를 빌드해봤더니 여기저기 삑사리나면서 안된다.

그래서 나는 손으로 직접 컴파일하고 묶어다가, 직접 만든 lib 폴더에 정리했다.
대충 이런식으로 했다.

일단 위의 링크에서 다운로드를 하든, 깃헙으로 가든 해서 소스를 전부 받고 압축도 풀면 된다.

//src 폴더로 이동해서 헤더파일도 옮겨놓고
gcc -c *.c

//링크해서 라이브러리를 만든다.
ar cvr libCello.lib *.o

비주얼 스튜디오는 사용이 불가하다. 그래서 나는 Clion로 돌렸다.
근데 Clion도 디폴트 설정이 msvc라서 따로 minGW 깔아서 설정해줘야한다.

그리고 윈도우에서는 디버깅 스택트레이스 출력을 위해서 DbgHelp라는 라이브러리를 추가로 요구하는데...

나같은 경우에는 기존 시스템 폴더에 dll만 있고 .lib가 없었다.
게다가 저 아래에 있는 것들은 다른 라이브러리에 딸려있던 거라...
그냥 가이드에서 설명하는 대로 그냥 매크로(CELLO_NSTRACE) 하나 놔서 기능 제거하고 돌리려고 했는데 그래도 안됐다. 왜지??

그래서 그냥 저기 부스트에 있던 .Lib 하나 땡겨썼다.
CMake는 대충 이런식이면 된다.

cmake_minimum_required(VERSION 3.12)
project(C_Test C)

set(CMAKE_C_STANDARD 11)

#헤더 추가
include_directories("C:/Users/selab/Desktop/Library/libCello-2.1.0/include")

add_executable(C_Test main.c)
# add_executable 뒤에 붙여야함
target_link_libraries(C_Test "C:/Users/selab/Desktop/Library/libCello-2.1.0/lib/libCello.lib")
target_link_libraries(C_Test "C:/Users/selab/Desktop/Library/libCello-2.1.0/lib/DbgHelp.lib")

잘 된다.

참고로 main 함수의 파라미터 타입은 저걸로 고정해야한다.
왜인지는 모르겠지만 조금만 바뀌어도 이런저런 에러를 뱉는다...


변수 선언은 var로 한다. 어떻게 구현한건지는 모르겠다.
그리고 C의 기본타입들을 래핑해서 쓰는데...
아래 코드에 쓰인 Int는 64비트 정수다.

비슷하게 실수도 래퍼 타입으로 Float가 있는데, 이건 내장 타입이 double이다.
근데 래퍼 타입들에 기능들을 막 그렇게 잘 넣어놓진 않은 것 같다. 제대로 연산을 하려면 꺼내서 써야한다.
그리고 new를 쓰면 객체가 가비지 컬렉터에 들어간다.

문자열 타입도 만들어놨다.
문서에 따르면 스택에 할당될 수도 있고 힙에 할당될 수도 있다고 한다.
어떻게 관리하는거지?

필수적인 자료구조들도 만들어놨다.
간소하게 동적배열, 연결리스트, 해시테이블, 트리 정도만 있는것 같다.
아래는 동적배열인 Array다. 문서에서도 std::vector와 동등하다고 한다.


연결리스트 List다. stl과는 다르게 정렬 기능이 없다.


아래는 트리맵 Tree다.
레드블랙트리로 구현했다고 한다

반복할 때는 역순으로 보여준다.
중복은 허용되지 않는다. 같은 키값이 들어와도 나중 값으로 덮힌다.


해시맵은 Table이다.
해시테이블도 뭐 사용법은 트리맵과 똑같다.
cello에서 구현된 타입들은 전부 hash를 구현하도록 약속되어있기 때문에, 자동으로 해싱이 된다.


가비지컬렉터에 대한 간단한 정리다!
앞서 언급했듯이 기본적으로 new를 쓰면 가비지 컬렉터에 객체가 들어간다. 가비지컬렉터에 들어간 객체라도 del로 수동 제거가 가능하다.
근데 이런 오버헤드를 아예 피하고 싶다면 아래와 같이 해서 가비지컬렉터를 멈추면 된다.
아니면 맨 위에 매크로로 CELLO_NGC를 추가해도 될거다.

var $gc = current(GC);
stop($gc);

인터페이스명중 하나가 Mark인걸 보니 마크앤스윕 방식을 쓰는것 같다?
가 아니라 문서를 보니 그게 맞다.
lazy한 RAII 방식으로 구현했다고 한다. 할당된 객체가 이름을 잃을 때마다 소멸자가 호출되게 해서 GC가 기록한 값과 비교하고... 그런거같다.


c++의 unique_ptr에 해당되는 Box도 있다.
이름은 Rust에서 따왔지 싶다?
GC의 성능 낭비가 싫으면 가비지 컬렉션을 끄고 이걸 쓰면 된다.

이런거 말고도 더 있긴 한데 그건 나중에...