C는 저수준 언어로 거의 이식 가능한 어셈블러이므로 데이터 구조와 언어 구조가 금속에 가깝습니다 (데이터 구조는 하드웨어와 ABI가 부과하는 패딩, 정렬 및 크기 제약을 제외하고 숨겨진 비용이 없습니다 ). 따라서 C에는 기본적으로 동적 입력이 없습니다. 그러나 필요한 경우 모든 값이 일부 유형 정보 (예 : ...)로 시작하는 집계 라는 규칙 을 채택 할 수 있습니다 . 사용 -s와 (배열과 같은 것들을) 가요 성 부재 배열 에서 같은 배열의 크기를 포함.enum
union
struct
(C로 프로그래밍 할 때는 특히 사전 및 사후 조건 및 불변 인과 같은 유용한 규칙을 정의, 문서화 및 준수하는 것이 귀하의 책임입니다. 또한 C 동적 메모리 할당 에는 free
힙이있는 malloc
메모리 영역을 누가 사용해야하는지에 대한 명시 적 규칙이 필요 합니다)
따라서 박스형 정수, 문자열 또는 어떤 종류의 구성표 와 같은 기호 또는 값의 벡터 인 값 을 나타 내기 위해 개념적으로 유형 결합으로 시작되는 태그 결합 (포인터 결합으로 구현 됨)을 개념적으로 사용합니다. -예 :
enum value_kind_en {V_NONE, V_INT, V_STRING, V_SYMBOL, V_VECTOR};
union value_en { // this union takes a word in memory
const void* vptr; // generic pointer, e.g. to free it
enum value_kind_en* vkind; // the value of *vkind decides which member to use
struct intvalue_st* vint;
struct strvalue_st* vstr;
struct symbvalue_st* vsymb;
struct vectvalue_st* vvect;
};
typedef union value_en value_t;
#define NULL_VALUE ((value_t){NULL})
struct intvalue_st {
enum value_kind_en kind; // always V_INT for intvalue_st
int num;
};
struct strvalue_st {
enum value_kind_en kind; // always V_STRING for strvalue_st
const char*str;
};
struct symbvalue_st {
enum value_kind_en kind; // V_SYMBOL
struct strvalue_st* symbname;
value_t symbvalue;
};
struct vectvalue_st {
enum value_kind_en kind; // V_VECTOR;
unsigned veclength;
value_t veccomp[]; // flexible array of veclength components.
};
일부 값의 동적 유형을 얻으려면
enum value_kind_en value_type(value_t v) {
if (v.vptr != NULL) return *(v.vkind);
else return V_NONE;
}
다음은 벡터에 대한 "동적 캐스트"입니다.
struct vectvalue_st* dyncast_vector (value_t v) {
if (value_type(v) == V_VECTOR) return v->vvect;
else return NULL;
}
벡터 내부의 "안전한 접근 자":
value_t vector_nth(value_t v, unsigned rk) {
struct vectvalue_st* vecp = dyncast_vector(v);
if (vecp && rk < vecp->veclength) return vecp->veccomp[rk];
else return NULL_VALUE;
}
일반적으로 static inline
일부 헤더 파일에서 와 같이 대부분의 짧은 기능을 정의 합니다.
BTW, Boehm의 가비지 콜렉터 를 사용할 수 있으면 상위 레벨 (하지만 안전하지 않은) 스타일로 아주 쉽게 코딩 할 수 있으며 여러 Scheme 인터프리터가 그런 식으로 수행됩니다. 가변 벡터 생성자는
value_t make_vector(unsigned size, ... /*value_t arguments*/) {
struct vectvalue_st* vec = GC_MALLOC(sizeof(*vec)+size*sizeof(value));
vec->kind = V_VECTOR;
va_args args;
va_start (args, size);
for (unsigned ix=0; ix<size; ix++)
vec->veccomp[ix] = va_arg(args,value_t);
va_end (args);
return (value_t){vec};
}
세 개의 변수가 있다면
value_t v1 = somevalue(), v2 = otherval(), v3 = NULL_VALUE;
당신은 그들을 사용하여 그들로부터 벡터를 구축 할 수 있습니다 make_vector(3,v1,v2,v3)
Boehm의 가비지 수집기를 사용하지 않으려면 (또는 직접 디자인) 소멸자를 정의하고 메모리를 누가, 어떻게, 언제 기억해야하는지 문서화하는 데 매우주의해야합니다 free
. 이 예를 참조하십시오 . 따라서 위 malloc
대신에 (그러나 실패에 대해 테스트 할 수는 있지만) GC_MALLOC
소멸자 함수를 신중하게 정의하고 사용해야합니다.void destroy_value(value_t)
C의 강점은 위와 같은 코드를 가능하게하고 자신의 규약 (특히 소프트웨어)을 정의하기에 충분히 낮은 수준입니다.