Better C
Better C
Better C는 D 런타임 라이브러리에 의존하지 않고, 오직 C 런타임 라이브러리만으로 동작하도록 D를 잘라낸 부분집합이에요. 이 장에서는 BetterC가 무엇인지, 어떤 기능을 유지하고 어떤 기능을 사용할 수 없게 되는지, 그리고 어떻게 활용하는지를 전반적으로 살펴봐요.
본문
BetterC는 D 런타임 라이브러리에 의존하지 않고, 오직 C 런타임 라이브러리만 의존하는 D의 부분집합(subset)이에요.
경고(Warning): D 런타임 라이브러리와 표준 라이브러리는 링크되지 않지만, 여러 패키지(
core.*와std.*)를 import 하고 본문이 없는 일부 템플릿·타입·함수 선언을 사용하는 것은 여전히 가능해요. 다만 이런 라이브러리들은 BetterC를 위해 작성된 것이 아니므로, 어떤 심볼을 써야 할지는 직접 판단해야 해요. 난해한 컴파일러나 링커 오류가 나올 수 있다고 감안하세요.
링크 (Linking)
C 함수와 C 라이브러리를 D 프로그램에 링크하는 것은 아주 간단해요. 하지만 D 함수와 D 라이브러리를 C 프로그램에 링크하는 것은 간단하지 않아요.
D 프로그램은 일반적으로 다음을 요구해요.
- D 런타임 라이브러리가 링크되어 있어야 한다 — 핵심 언어의 많은 기능이 런타임 라이브러리 지원을 필요로 하기 때문이다.
main()함수가 D로 작성되어, 필수 런타임 라이브러리 지원이 제대로 초기화되도록 해야 한다.
D 함수와 D 라이브러리를 C 프로그램에 링크하려면, 필요한 런타임 라이브러리가 오직 C 런타임 라이브러리뿐이면 돼요. 이 요구를 충족하도록 D를 정의한 부분집합이 바로 BetterC예요.
Better C
구현 정의(Implementation Defined): BetterC는 일반적으로 구현체에서
-betterC명령줄 플래그를 설정해 활성화해요.
BetterC가 활성화되면, 미리 정의된 버전(version) D_BetterC를 조건부 컴파일에 사용할 수 있어요.
C main() 함수를 제공하면 프로그램 전체를 BetterC로 작성할 수 있어요.
extern(C) void main()
{
import core.stdc.stdio : printf;
printf("Hello betterC\n");
}
> dmd -betterC hello.d && ./hello
Hello betterC
프로그램을 이 정도의 런타임 기능 부분집합으로 제한하는 것은, 그러한 기능을 쓰는 것이 실용적이지 않거나 아예 불가능한 제약된 환경을 대상으로 할 때 유용해요.
BetterC는 기존의 더 큰 프로젝트에 D 라이브러리를 내장(embedding)하기 쉽게 만들어 주는데, 그 이유는 이래요.
- 빌드 시스템 수준에서의 통합 과정을 단순화한다.
- 라이브러리 사용 전에 초기화 단계를 수행하지 않거나 삽입하기 어려운 상황에서, 라이브러리를 호출할 때 Druntime이 제대로 초기화되도록 보장해야 할 필요를 없앤다.
- 메모리 관리 전략을 섞는 것(GC + 수동 메모리 관리)은 까다로울 수 있는데, 방정식에서 D의 GC를 제거하는 게 때로는 그만한 가치가 있다.
참고(Note): BetterC와 ImportC는 아주 달라요. ImportC는 실제 C 컴파일러예요. BetterC는 오직 C 표준 라이브러리의 존재에만 의존하는 D의 부분집합이에요.
유지되는 기능 (Retained Features)
거의 전체 언어가 그대로 사용 가능해요. 주요 항목은 이래요.
- 컴파일 타임 기능의 제한 없는 사용
- 완전한 메타프로그래밍 수단(metaprogramming)
- 중첩 함수, 중첩 구조체, 델리게이트(delegate), 람다(lambda)
- 멤버 함수, 생성자, 소멸자, 연산자 오버로딩 등
- 전체 모듈 시스템
- 배열 슬라이싱(slicing)과 배열 경계 검사
- RAII (예, 예외 없이도 동작해요)
scope(exit)- 메모리 안전 보호(Memory safety)
- C++와의 연동(Interfacing to C++)
- COM 클래스와 C++ 클래스
- assert 실패는 C 런타임 라이브러리로 보내진다
- 문자열로 하는 switch
- final switch
- unittest
- printf 포맷 검증
-betterC에서 유닛 테스트 실행하기 (Running unittests in -betterC)
테스트는 -betterC 플래그 없이도 할 수 있지만, 때로는 테스트 스위트(testsuite)를 -betterC로도 실행하는 것이 바람직해요. unittest 블록은 getUnitTests 특성(trait)으로 나열할 수 있어요.
unittest
{
assert(0);
}
extern(C) void main()
{
static foreach(u; __traits(getUnitTests, __traits(parent, main)))
u();
}
> dmd -betterC -unittest -run test.d
dmd_runpezoXK: foo.d:3: Assertion `0' failed.
다만 -betterC에서는 assert 표현식이 Druntime의 assert를 쓰지 않고, 대신 C 런타임 라이브러리의 assert로 보내져요.
사용할 수 없는 기능 (Unavailable Features)
BetterC에서는 사용할 수 없는 D 기능들이에요.
- 가비지 컬렉션(Garbage Collection)
- TypeInfo와 ModuleInfo
- 클래스(Classes)
- 내장 스레딩 (예:
core.thread) - 동적 배열 (정적 배열의 슬라이스와 포인터는 동작해요)
- 연관 배열(Associative arrays)
- 예외(Exceptions)
synchronized와core.sync- 정적 모듈 생성자·소멸자(Static module constructors or destructors)
더 알아보기 (Learn more)
- 조건부 컴파일 (Conditional Compilation) —
D_BetterC버전과version(...)사용 - C와의 연동 (Interfacing to C) —
extern(C)링크 - ImportC — BetterC와 달리 실제 C 컴파일러인 ImportC