C에서 union으로 타입 안전 제네릭 자료구조 만드는 4단계 기법
- Daniel Hooper가 union으로 타입 정보를 자료구조에 묶어 C에서 컴파일 타임 타입 검사를 받는 제네릭 자료구조 기법을 소개. 같은 방식의 사례를 다른 곳에서 본 적 없다고 밝힘
- 매크로 헤더를 타입마다 반복 include하는 level 0 방식은 타입과 함수 정의를 찾기 어렵고, 코드 완성 지원이 약하고, 같은 함수가 복사돼 바이너리와 빌드 시간이 늘고, Foo_list_prepend()처럼 타입 접두어가 붙은 함수명을 강제함
- level 1 void* 방식은 노드마다 할당 2회와 순회 시 캐시 미스 2회를 유발. level 2는 flexible array member로 노드와 데이터를 한 번에 할당해 이 문제를 없애지만 데이터 크기를 넘겨야 하고 memcpy가 필요함
- list_alloc_front로 노드 메모리를 직접 초기화하면 memcpy를 피할 수 있고, malloc 대신 arena 할당자를 쓰라고 권함
- 예제는 연결 리스트지만 map, 배열, 이진 트리 등 어떤 자료구조에도 적용된다고 밝힘
Hacker News opinions
David Priver의 Templates in C도 봐라, 링크 걸어둠. 걔가 C에 reflection 추가하기, _Generic 타입 재화, C2y REPL 인터프리터 DrC까지 만들었더라. 글 스타일이 간결하고 군더더기 없어서 좋음.
ㅋㅋ 어느 순간 C로 작은 컴파일러 만드는 수준까지 가네. 제네릭은 매크로로 하면 그렇게 어렵지도 않고 많이들 원하는 기능인데 reflection은 좀 웃기긴 함.
어 그거 나임! 내 글 좋아해줘서 반갑다.
나도 타입 안전 컨테이너 타입 정리한 글 썼는데 C23 변경사항 반영했고 복잡한 타입에도 잘 맞게 고쳤음. 링크 남겨둠.
(1 ? (item) : (list)->payload) 트릭 신기하더라. 최적화로 사라지지만 타입 비교는 그 전에 일어남. 좀 트릭 같긴 한데 되긴 되네.
컴파일은 되고 평가는 안 되는 표현식은 C++ 템플릿 메타프로그래밍의 기본임.
요즘은 좀 억지 트릭인 것 같음. 나도 제목 보고 _Generic 쓸 줄 알았는데 아니었음.
C에 기능을 계속 추가해서 C++처럼 새 언어를 만드는 게 가능한가?
Objective-C도 그렇게 나왔는데 사람들이 C로 그걸 다시 나쁘게 재발명하고 있음.
그런 언어 이미 많음. Zig 같은 것도 있고.
매크로 핵 진짜 싫음. 대부분 컨테이너 하나만 필요하니까 그냥 즉석에서 구현하는 게 더 깔끔함.
C++ 안 건드리려고 저 지경까지 가는 거임.
몇 년 동안 해봤는데 완전 구림. 제대로 된 제네릭 자료구조 필요하면 그냥 C++ 템플릿 써라. C는 결함 있는 언어임.
다른 언어에서 수년 전에 해결한 걸 왜 C 매크로로 재발명하는지 모르겠음. C++ 쓰면 되는데, 기존 C 코드베이스에 넣기도 꽤 간단하고.
C++ 런타임이랑 표준 라이브러리가 워낙 복잡해서 가능하면 안 건드리려 함. "C++도 단점이 있다"는 말은 눈알 빼는 것도 단점 있다는 소리랑 비슷함.
배열 컨테이너 하나 쓰자고 C 코드베이스를 C++로 옮기긴 싫음. 코드베이스를 C++의 엄격한 부분집합으로 유지하기가 매우 어려움.
C++ 많이 써봤는데 C++ 쪽이 훨씬 더 엉망임. C 코드베이스에 C++ 도입한 프로젝트에 기여하는데 안 했으면 싶음.
C99의 VLA 추가는 실수였다고 보는 C 프로그래머가 많던데, 이 접근법의 단점은 뭔가?
그래서 C11에서 선택적 부속서가 됐고 구글이 리눅스 커널에서 VLA를 다 걷어내는 데 돈을 냈음.
이 맥락에서 VLA랑 무슨 상관인지 모르겠음. VLA 필요하면 쓰면 되고 대부분 대안보다 나음.