이 문서는 CCTL(C Template Library) 프로젝트의 아키텍처, 설계 의도, 매크로 메타프로그래밍 규칙, 코딩 컨벤션 및 개발 지침을 AI 에이전트와 기여자를 위해 정리한 기술 가이드입니다.
CCTL은 최신 C 언어 표준(C23 지향) 환경에서 C++의 STL(Standard Template Library)과 유사한 타입 안전(Type-Safe) 제네릭 자료구조 및 컨테이너를 제공하는 템플릿 라이브러리입니다.
- 최신 C 표준 지향 (Targeting C23 & Future Standards): CCTL은 ISO/IEC 9899:2024(C23)을 기본 설계 및 빌드 타깃으로 지향하며, 향후 제정되는 최신 C 표준 사양을 적극 수용합니다.
- 최소 요구 표준 및 컴파일러 플래그:
- C11
_Generic디스패처,<uchar.h>,<stdbool.h>,<stdint.h>를 기반으로 동작하므로 최소 C11 이상의 컴파일러가 필요하며, 기본 권장 표준은 **C23 (-std=c23//std:clatest)**입니다. - C23 미지원 컴파일러 대응 (
-std=c2x): 사용 중인 컴파일러 버전(예: GCC 913, Clang 917 등)이 아직-std=c23옵션을 인식하지 못할 경우, C23 드래프트 임시 명칭인-std=c2x플래그를 대체 사용해야 합니다.
- C11
- 레거시 C 문법 지양: 타입 안전성이 결여된 구형 C90/C99 방식이나
void*만능 캐스팅 대신, 최신 C 표준이 제공하는 강력한 컴파일 타임 기능과 매크로 메타프로그래밍을 조합하여 제로 오버헤드를 달성합니다.
- 순수 모던 C 기반 제네릭 구현 (Pure Modern C Generic Metaprogramming)
- C++ 컴파일러나 런타임 의존성 없이 표준 C 전처리기(Preprocessor)와
_Generic문법만을 활용하여 컴파일 타임 타입 검사 및 전용 함수를 생성합니다.
- C++ 컴파일러나 런타임 의존성 없이 표준 C 전처리기(Preprocessor)와
- 헤더/소스 분리형 인스턴스화 모델 (Separation of Declaration & Implementation)
- 단순 매크로 치환 방식의 중복 심볼(ODR 위반) 및 코드 블로트(Code Bloat)를 방지하기 위해, 전방 선언(
_fd), 헤더 선언(_imp_h), 소스 구현(_imp_c)으로 템플릿 인스턴스화 단계를 엄격히 분리합니다.
- 단순 매크로 치환 방식의 중복 심볼(ODR 위반) 및 코드 블로트(Code Bloat)를 방지하기 위해, 전방 선언(
- 제로 런타임 오버헤드 (Zero Runtime Overhead & Inline Optimization)
void*간접 참조를 최소화하고, 타입별 전용 구조체와 인라인 함수(static inline)를 생성하여 최적의 성능과 캐시 지역성을 보장합니다.
- 일관된 API 및 이터레이터 인터페이스 (Uniform Container & Iterator Protocol)
- 모든 컨테이너는 공통된 수명주기 함수(
init,free,clear)와 표준 이터레이터(begin,rbegin,next,prev,foreach,rforeach) 인터페이스를 따릅니다.
- 모든 컨테이너는 공통된 수명주기 함수(
cctl/
├── cctl.h # 핵심 전처리기 매크로 (토큰 연결, 이름 맹글링, 포인터/문자열 기본 타입 정의)
├── utils.h # C11/C23 _Generic 기반 기본 비교/복사/해제 함수 디스패처 및 메모리 유틸리티
├── hasher.h # 32비트 FNV-1a, MurmurHash3, SipHash 알고리즘 및 _Generic 해시 디스패처
├── vector.h # 동적 배열 (Dynamic Array)
├── deque.h # 청크 기반 양방향 큐 (Double-Ended Queue)
├── list.h # 이중 연결 리스트 (Doubly Linked List)
├── heapq.h # 2진 힙 기반 우선순위 큐 (Priority Queue: Min/Max Heap)
├── rbt.h # 레드-블랙 트리 (Red-Black Tree, 정렬된 Key-Value 맵)
├── hashmap.h # Open Addressing 선형 탐색 해시맵 (Key-Value Map)
├── trie.h # Radix-256 트라이 (문자열 Prefix 트리)
├── critbit.h # DJB Crit-Bit 트리 (문자열 Key-Value 맵)
├── optional.h # 널 가능 값 래퍼 (Optional/Nullable Value Container)
├── result.h # 성공/실패 결과 래퍼 (Result/Expected Value Container)
├── str.h # 동적 기본 문자열 컨테이너 (basic_string)
├── test/ # 단위 테스트 및 검증 코드 디렉터리
├── LICENSE.txt # MIT 라이선스
├── README.md # 사용자 매뉴얼 및 컨테이너 API 명세
└── AGENTS.md # AI 에이전트 및 기여자용 아키텍처/개발 가이드
graph TD
cctl_h["cctl.h (Base Macros & Types)"] --> utils_h["utils.h (Memory & Generic Dispatch)"]
cctl_h --> vector_h["vector.h"]
cctl_h --> deque_h["deque.h"]
cctl_h --> list_h["list.h"]
cctl_h --> optional_h["optional.h"]
cctl_h --> result_h["result.h"]
cctl_h --> str_h["str.h"]
utils_h --> hasher_h["hasher.h (Hash Algorithms)"]
utils_h --> heapq_h["heapq.h"]
utils_h --> rbt_h["rbt.h"]
hasher_h --> hashmap_h["hashmap.h"]
cctl_h --> trie_h["trie.h"]
cctl_h --> critbit_h["critbit.h"]
CCTL은 전처리기 토큰 연결(##)을 통해 타입별 전용 심볼을 생성합니다.
- 단일 타입 컨테이너:
cctl_join(T, NAME)⇒<T>_<NAME>- 예:
vector(int)⇒int_vector - 예:
vector_iterator(int)⇒int_vector_iterator - 예:
vector_func(push_back, int)⇒int_vector_push_back - 예:
critbit(int)⇒int_critbit - 예:
critbit_func(insert, int)⇒int_critbit_insert
- 예:
- 다중 타입(Key-Value) 컨테이너:
cctl_join3(K, V, NAME)⇒<K>_<V>_<NAME>- 예:
hashmap(cstring, int)⇒cstring_int_hashmap - 예:
rbt(int, double)⇒int_double_rbt - 예:
hashmap_func(insert, cstring, int)⇒cstring_int_hashmap_insert
- 예:
다중 파일 프로젝트에서 컴파일 오류와 중복 정의(Symbol Duplication)를 피하기 위해 다음 패턴을 준수해야 합니다.
| 매크로 단계 | 역할 | 위치 | 예시 |
|---|---|---|---|
*_fd(...) |
불완전 타입/구조체 전방 선언 (Forward Declaration) | 헤더 (.h) |
vector_fd(int); |
*_imp_h(...) |
구조체 정의 + 함수 프로토타입 선언 | 헤더 (.h) |
vector_imp_h(int); |
*_imp_c(...) |
함수 본문 구현 (1개 번역 단위에만 작성) | 소스 (.c) |
vector_imp_c(int); |
-
cctl_define.h(헤더 파일)#pragma once #include "cctl/vector.h" #include "cctl/hashmap.h" vector_fd(int); vector_imp_h(int); hashmap_fd(cstring, int); hashmap_imp_h(cstring, int);
-
cctl_define.c(구현 소스 파일)#include "cctl_define.h" vector_imp_c(int); hashmap_imp_c(cstring, int);
-
main.c(사용자 코드)#include <stdio.h> #include "cctl_define.h" int main(void) { vector(int) v; vector_init(int, &v); vector_push_back(int, &v, 42); printf("Value: %d\n", *vector_at(int, &v, 0)); vector_free(int, &v); return 0; }
C 전처리기는 토큰 연결 시 * 문자를 사용할 수 없습니다 (int*##_vector 불가). 포인터 타입을 컨테이너에 담으려면 반드시 사전 typedef를 거쳐야 합니다.
-
포인터 타입 정의 매크로:
// cctl_ptr_def(T) -> typedef T* T_ptr; cctl_ptr_def(MyStruct); vector_fd(cctl_ptr(MyStruct)); vector_imp_h(cctl_ptr(MyStruct));
-
기본 제공 문자열 타입 별칭:
cstring⇒char*(Null-terminated C String)u16cstring⇒char16_t*(UTF-16 String)u32cstring⇒char32_t*(UTF-32 String)
CCTL은 다양한 선언 및 초기화 방식을 통일된 패턴으로 제공합니다.
- 기본 초기화 (
*_init):- 포인터와 크기 필드를
0/NULL상태로 리셋하는 순수void함수입니다. - 힙 메모리를 할당하지 않으므로 항상 성공하며
free내부에서도 재호출되어 자원을 리셋합니다. - 예:
vector_init(int, &v);
- 포인터와 크기 필드를
- 값 반환형 생성자 (
*_new):- 초기화된 컨테이너 구조체를 값으로 직접 반환하여 선언과 동시에 대입할 수 있습니다.
- 시퀀스 컨테이너(
vector,deque,list,str)는cctl_dispatch를 통해 크기 인자(size)를 선택적으로 전달할 수 있습니다. - 예:
vector(int) v1 = vector_new(int);(빈 벡터 생성) - 예:
vector(int) v2 = vector_new(int, 10);(10개 원소가 0으로 초기화된 벡터 생성)
- 리터럴 초기화 및 확장 (
*_from_items,*_extend_items):- C99 복합 리터럴(Compound Literal)과
sizeof를 활용하여 가변 인자로 항목을 전달받아 컨테이너를 생성하거나 벌크 추가합니다. - 예:
vector(int) v = vector_from_items(int, 1, 2, 3, 4, 5); - 예:
vector_extend_items(int, &v, 6, 7, 8);(추가 성공 시true, 실패 시false반환)
- C99 복합 리터럴(Compound Literal)과
- OOM 할당 실패 시 안전 롤백 (Rollback to Empty State):
new(size)및from_items(...)실행 중 내부 메모리 할당(resize,extend_items등)이 실패하면, 이미 부분 할당되었던 메모리를 즉시 내부에서free하고 **완전한 빈 상태(size = 0, NULL)**로 롤백하여 반환합니다. 이를 통해 메모리 누수를 100% 방지하고 더블 프리로부터 안전합니다.
- 가변 인자 매크로 디스패처 (
cctl_va_count,cctl_dispatch):cctl.h에 내장된 0~64개 가변 인자 카운터 매크로를 통해 인자 개수에 따라 적절한 접미사 매크로(BASE_N)로 컴파일 타임 분기합니다.
CCTL은 내장 기본 타입 및 문자열 타입에 대해 컴파일 타임에 자동으로 기본 함수 포인터를 바인딩합니다.
- 지원되는 기본 타입:
int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,int64_t,uint64_t,float,double,cstring,u16cstring,u32cstring. - 제공되는 디스패처 매크로:
cctl_get_default_compare_func(T):<및>연산 기반 비교 함수 (문자열은strcmp/ 메모리 비교).cctl_get_default_copy_func(T): 기본 값 복사 (문자열은 힙 동적 할당 기반 Deep Copy).cctl_get_default_free_func(T): 기본 타입은 no-op, 문자열은free()호출.cctl_get_default_hash_func(T): 32비트 MurmurHash3 기반 해시 함수 반환.
사용자 정의 구조체나 복합 포인터 타입을 hashmap, rbt, heapq 등에서 사용할 때는 초기화 후 명시적으로 함수 포인터를 등록해야 합니다:
hashmap_init(MyKey, MyVal, &hm);
hashmap_set_hash_func(MyKey, MyVal, &hm, my_key_hash_fn);
hashmap_set_compare_func(MyKey, MyVal, &hm, my_key_compare_fn);
hashmap_set_copy_func(MyKey, MyVal, &hm, my_key_copy_fn);
hashmap_set_free_func(MyKey, MyVal, &hm, my_key_free_fn);모든 이터레이터 지원 컨테이너(vector, deque, list, rbt, hashmap, trie, critbit)는 표준 이터레이터 규격을 준수합니다.
*_begin(T, p_c): 첫 번째 유효 요소를 가리키는 이터레이터 반환.*_end(T, p_c): 마지막 요소의 다음(past-the-end / 센티넬)을 가리키는 이터레이터 반환.*_rbegin(T, p_c): 역방향 첫 번째(마지막) 유효 요소를 가리키는 이터레이터 반환.*_rend(T, p_c): 역방향 마지막 요소의 이전(before-the-first / 센티넬)을 가리키는 이터레이터 반환.*_iterator_is_valid(T, p_it): 현재 이터레이터가 유효한 요소를 가리키는지 확인 (bool).*_iterator_is_equal(T, p_it1, p_it2): 두 이터레이터가 동일한 컨테이너 및 위치/노드를 가리키는지 확인 (bool).*_iterator_get(T, p_it): 현재 요소의 포인터 반환 (T*또는pair*).*_iterator_get_key(T, p_it): 현재 요소의 키를 새로 동적 할당(malloc) 및 복사하여 반환 (호출자가free).*_iterator_get_key_ref(T, p_it): 내부적으로 키를 보관하는 컨테이너(critbit,rbt,hashmap)에서 현재 요소의 키에 대한 직접 참조/포인터 반환.*_iterator_next(T, p_it): 다음 요소로 전진.*_iterator_prev(T, p_it): 이전 요소로 후진.
// 정방향 전체 순회
vector_foreach(int, &v, it) {
int value = *vector_iterator_get(int, &it);
printf("%d\n", value);
}
// 역방향 전체 순회
vector_rforeach(int, &v, it) {
int value = *vector_iterator_get(int, &it);
printf("%d\n", value);
}
// [first, last) 반열린 구간(Range) 순회 및 lower_bound/upper_bound 활용 (RBT 예시)
rbt_iterator(int, int) first = rbt_lower_bound(int, int, &tree, 20); // key >= 20
rbt_iterator(int, int) last = rbt_upper_bound(int, int, &tree, 40); // key > 40
for (rbt_iterator(int, int) it = first;
!rbt_iterator_is_equal(int, int, &it, &last);
rbt_iterator_next(int, int, &it)) {
printf("Key: %d, Val: %d\n", it.p_node->data.key, it.p_node->data.value);
}| 컨테이너 | 설명 | 시간 복잡도 (접근 / 삽입 / 삭제) | 주요 특이사항 |
|---|---|---|---|
vector(T) |
연속 메모리 기반 동적 배열 |
|
지수적(2배) 용량 증가, vector_at, reserve, resize 지원 |
deque(T) |
고정 청크(512단위) 기반 양방향 큐 |
|
잦은 앞/뒤 삽입 시 메모리 재할당 최소화 |
list(T) |
이중 연결 리스트 |
|
노드 단위 힙 할당, 노드 캡슐화 및 이터레이터/포인터 기반 삽입/삭제 지원 |
heapq(T) |
2진 힙 기반 우선순위 큐 |
|
is_min_heap 플래그로 Min-Heap / Max-Heap 전환 가능 |
rbt(K, V) |
레드-블랙 트리 (정렬 Key-Value) |
|
센티넬 노드 p_nil을 공유하여 경계 검사 최적화, In-Order 정렬 순회 |
hashmap(K, V) |
Open Addressing 선형 탐색 해시맵 |
|
톰스톤(Tombstone) 삭제 상태(CCTL_HASHMAP_DELETED) 관리, 부하율 50% 시 리사이즈 |
trie(T) |
256-ary Radix 문자열 트라이 |
|
Prefix 탐색, 사전순 정렬 순회, trie_iterator_get_key로 키 역추적 |
critbit(V) |
DJB Crit-Bit 트리 (문자열 Key-Value) |
|
Tagged Pointer 노드, Prefix 탐색, |
optional(T) |
값의 존재 유무 래퍼 |
|
has_value, value_or, some, none 제공 |
result(T, E) |
성공/실패 결과 래퍼 |
|
is_ok, is_err, unwrap, unwrap_err, unwrap_or, ok, err 제공 |
str.h |
가변 길이 동적 문자열 |
|
basic_string(char) 기반, 문자열 버퍼 관리 |
새로운 컨테이너를 추가하거나 기존 코드를 수정할 때 AI 에이전트는 다음 규칙을 엄격히 준수해야 합니다.
함수의 매개변수(Parameter)와 내부 지역변수(Local Variable)는 타입과 참조 형태에 따라 다음 접두사를 일관되게 적용합니다.
| 접두사 | 타입 및 메모리 참조 형태 | 실제 C 타입 예시 | 변수명 예시 |
|---|---|---|---|
| (없음) | 일반 값 / 구조체 (Value) | int, size_t, pair |
index, count, capacity, item |
p_ |
단일 포인터 (Pointer) | int*, vector*, node* |
p_v, p_hm, p_node, p_data, p_it |
pp_ |
이중 포인터 (Pointer to Pointer) | void**, node** |
pp_parent, pp_root, pp_node |
a_ |
값의 고정 배열 (Array) | int[10], char[256] |
a_items, a_buffer, a_bytes, a_slots |
ap_ |
포인터의 배열 (Array of Pointers) | char*[10], node*[32] |
ap_strings, ap_nodes |
fp_ |
함수 포인터 (Function Pointer) | int (*)(int, int) |
fp_comp_func, fp_hash_func, fp_copy_func |
임의의 자음 축약이나 불명확한 줄임말을 지양하고, 공인된 표준 관용 축약어와 **온전한 영단어(Full Word)**를 명확히 구분하여 사용합니다.
-
공인 표준 단축어 (Established Standard Abbreviations)
- 순회/위치 (4글자 대칭):
prev(previous지양),curr(current지양),next - C 언어 및 시스템 핵심:
char(character지양),ptr(pointer지양),func(function/fn지양),temp(temporary/tmp지양) - C 언어 및 시스템 핵심:
char(character지양),ptr(pointer지양),func(function,fn지양),temp(temporary,tmp지양) - 수학 및 극값:
min(minimum지양),max(maximum지양) - I/O 및 시스템 동작:
src(source지양),dest(destination/dst지양),dir(direction지양),init(initialize지양),alloc(allocate지양) - 역방향 접두사:
r*(rbegin,rforeach/reversed_*지양) - 컨테이너 주체 포인터:
p_v,p_hm,p_d,p_l,p_r,p_t,p_opt,p_it(1~2글자 이니셜 허용) - I/O 및 시스템 동작:
src(source지양),dest(destination,dst지양),dir(direction지양),init(initialize지양),alloc(allocate지양) - 역방향 접두사:
r*(예:rbegin,rforeach/reversed_*지양) - 컨테이너 주체 변수 및 포인터: 컨테이너를 다루는 주체 포인터(
p_v,p_hm,p_d,p_l,p_r,p_t,p_opt,p_it)뿐만 아니라, 해당 인스턴스를 직접 생성하여 다루는 지역변수명(v,hm,d,l,r,t,opt,it)에는 1~2글자 이니셜을 허용합니다 (예:vector(int) v = vector_new(int);).
- 순회/위치 (4글자 대칭):
-
완전한 단어 유지 (Full Word Mandate)
- 마땅한 표준 줄임말이 없는 명사는 임의로 자음만 따거나 2~3글자로 줄이지 않고 온전한 영단어를 유지합니다.
- 데이터 및 값:
data(❌dat),value(❌val),item(❌elem,element) - 수치 및 용량:
capacity(❌caps,cap),index(❌idx),count(❌cnt),length(❌len) - 결과 및 버퍼:
result(❌res,ret),buffer(❌buf)
-
매크로 인자: 대문자를 사용하며, 단일 타입은
T, Key-Value 컨테이너는K,V로 통일합니다 (T,K,V,FUNC). -
매크로 분류 및 대소문자 규약:
-
매크로 상수 (Macro Constants): 모두 대문자(
ALL_CAPS)를 사용합니다 (CCTL_HASHMAP_EMPTY,CCTL_RBT_RED,CCTL_RBT_BLACK). -
함수형 매크로 (Function-like Macros): 반환형이 존재하거나 특정 동작/연산을 수행하는 매크로로, **반드시 소문자(
lowercase_with_underscores)**로 작성합니다 (vector_init,critbit_insert,cctl_critbit_is_branch_node,cctl_critbit_to_branch_node,cctl_critbit_tag_branch_node,cctl_critbit_to_leaf_node). -
치환형 매크로 (Token Replacement Macros): 타입명 정의나 식별자 이름 생성/토큰 맹글링 등 단순 치환을 수행하는 매크로로, **반드시 소문자(
lowercase_with_underscores)**로 작성합니다 (vector,vector_func,vector_iterator,critbit,critbit_func,cctl_join,cctl_ptr).
-
매크로 상수 (Macro Constants): 모두 대문자(
-
네이밍 시 역할 중심 직관성 규칙:
- 내부 연산에 쓰이는 매크로라도 모호한
internal등의 단어 대신 그 역할과 동작이 이름에서 명확히 드러나도록 작성해야 합니다 (is_internal지양$\to$ is_branch_node지향).
- 내부 연산에 쓰이는 매크로라도 모호한
-
구조체 태그:
cctl_join(container(T), struct)규칙에 따라<T>_<container>_struct(또는<K>_<V>_<container>_struct)로 선언합니다. -
헤더 가드:
__CCTL_<MODULE>_H__형식을 준수합니다.
-
들여쓰기 (Tab Indentation Everywhere): C 소스/헤더 파일뿐만 아니라 마크다운(
.md) 문서를 포함한 모든 파일에서 들여쓰기 시 스페이스 대신 반드시 **탭(Tab,\t)**을 사용합니다. -
문서화 주석:
- 함수형 매크로: 반환형과 매개변수 타입을 포함한 가상 함수 시그니처(`/// ```c <return_type> <func_name>(...) ````) 및 동작 설명을 반드시 작성합니다.
- 치환형 매크로:
/// name(ARGS)⇒...형식으로 치환 결과 및 역할을 설명합니다. - 헤더 내
static inline비-매크로 함수: IDE/LSP 툴팁에서 C 정의가 직접 표시되므로, 별도의 가상 시그니처 블록 없이 함수의 목적과 역할을 간결하게 삼중 슬래시(///) 주석으로 설명합니다.
-
라이선스 헤더: 모든 헤더 파일 상단에 MIT 라이선스 식별자를 유지합니다:
// SPDX-License-Identifier: MIT // Copyright (c) 2021 Michael Bäck <mhcoma@gmail.com>
- NULL 검사: 컨테이너 포인터(
p_v,p_hm등) 및 이터레이터 포인터(p_it)는 함수 진입 시 항상 유효성을 검사해야 합니다. - 할당 실패 처리:
malloc,calloc,realloc호출 실패 시 이전 메모리를 온전히 유지하고false를 반환해야 합니다. - 초기화 및 리셋:
free호출 후 구조체 내부 포인터를 반드시NULL로 초기화(memset또는init호출)하여 더블 프리(Double Free) 및 댕글링 포인터를 방지해야 합니다. - API 서명 불변성: 기존 매크로의 인수 순서 및 반환 형식을 파괴하는 변경은 지양합니다.
test/ 디렉터리에 각 자료구조별 테스트 코드를 작성할 때, *_fd, *_imp_h, *_imp_c가 정상 작동하는지 분리 컴파일 및 단일 컴파일 모두 검증해야 합니다.
#include <assert.h>
#include <stdio.h>
#include "../vector.h"
vector_fd(int);
vector_imp_h(int);
vector_imp_c(int);
int main(void) {
vector(int) v;
vector_init(int, &v);
assert(vector_is_empty(int, &v));
for (int i = 0; i < 100; i++) {
assert(vector_push_back(int, &v, i));
}
assert(vector_size(int, &v) == 100);
assert(*vector_at(int, &v, 50) == 50);
int count = 0;
vector_foreach(int, &v, it) {
assert(*vector_iterator_get(int, &it) == count++);
}
vector_free(int, &v);
printf("vector test passed successfully!\n");
return 0;
}최신 C 표준(C23 기본 타깃)으로 컴파일을 수행합니다. 컴파일러가 -std=c23을 지원하지 않는 경우 -std=c2x를 사용합니다:
# GCC 최신 C23 컴파일 (c23 미지원 시 -std=c2x 대체)
gcc -std=c23 -Wall -Wextra -g test/test_vector.c -I. -o test/test_vector.exe
# (대체) gcc -std=c2x -Wall -Wextra -g test/test_vector.c -I. -o test/test_vector.exe
./test/test_vector.exe
# Clang 최신 C23 컴파일 (AddressSanitizer 포함, c23 미지원 시 -std=c2x 대체)
clang -std=c23 -Wall -Wextra -fsanitize=address -g test/test_vector.c -I. -o test/test_vector.exe
# (대체) clang -std=c2x -Wall -Wextra -fsanitize=address -g test/test_vector.c -I. -o test/test_vector.exe
./test/test_vector.exe
# MSVC (최신 C 표준 타깃)
cl.exe /std:clatest /W4 test\test_vector.c /I. /Fe:test\test_vector.exe
.\test\test_vector.exe프로젝트의 기존 커밋 히스토리를 반영하여 일관된 접두사를 사용합니다:
Add : <기능 설명>- 새로운 자료구조, 매크로, 테스트 추가Fix : <버그 설명>- 버그 수정, 오탈자 수정, 주석 보완Refactor : <리팩토링 내용>- 구조 개선 및 알고리즘 최적화