카테고리
게시일
Jan 25, 2025

리눅스 스터디 3주차에 발표자 팀원이 재미있는 코드 부분을 가져왔다.
아래는 linux kernel에서 에서 cgroup subsystem을 초기화하는 부분이다. 사실 cgroup subsystem 이 무엇인지는 이 글에서 중요한 내용은 아니고, 컨테이너 데이터를 차례로 순회하는 코드블럭, 즉 foreach 블럭을 c에서도 매크로를 이용해 멋들어지게 만들 수 있다는 점이 이 글을 쓰는 이유이다.
from kernel 6.8.1, /kernel/cgroup/cgroup.c
struct cgroup_subsys *ss; int i; // ... bla bla for_each_subsys(ss, i) { // bla bla cgroup의 ss를 초기화 if (ss->early_init) cgroup_init_subsys(ss, true); }
위 코드는 정의된 서브시스템의 각각의 정보를 가져온다. 일종의 for each 문으로 동작하며, 존재하는 ss 포인터에 한번에 하나씩 순회하면서 가져와서 아래 코드블럭을 실행한다.
/** * for_each_subsys - iterate all enabled cgroup subsystems * @ss: the iteration cursor * @ssid: the index of @ss, CGROUP_SUBSYS_COUNT after reaching the end */ #define for_each_subsys(ss, ssid) \ for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT && \ (((ss) = cgroup_subsys[ssid]) || true); (ssid)++)
실제 for_each_subsys는 매크로로 구현되어있으며, 그 실체는 for문의 머리부분이다. 실제로 iterator를 업데이트 하는 부분은 가운데 condition statement에서 일어난다.
이런식으로 만든것은 독립된 코드블럭을 만들어주기 위해 일종의 꼼수(?)를 쓴 것이다. 왜 세번째 부분(ssid++)에 넣어주지 않고 굳이 condition state에서 || true를 이용한 꼼수를 써주었냐 하면, consition state는 for문이 최초로 동작할 때 코드블럭보다 먼저 실행이 된다는 점을 이용한 것이다.
for(...) // 매크로부분, iterator를 for의 머리에서 전부 처리해주면 { // 블럭부분 // 위 for문에서 전부 처리해준 덕분에 이 부분은 마치 다른 언어의 foreach 블럭을 사용하는 것 처럼 자유로워진다. }
아래 글 참조
https://stackoverflow.com/questions/35381932/a-foreach-macro-with-a-break-or-continue-statement-in-c
C는 공부하면 공부할수록 매크로의 만능성에 감탄하게 되는 것 같다.