2012-06-21 4 views
0

여러 필드가있는 레코드를 저장하는 C 라이브러리가 있습니다. 스키마는 레코드의 각 필드 유형을 포함하여 텍스트 파일에서 읽습니다. C 런타임 유형 검사

내가 스키마 파일은 데 MyRecord의 각 필드는 int32_t 또는 MYSTRUCT을 유지할지 여부를 말한다

typedef enum my_type_enum 
{ 
    INT32, //32-bit integer 
    MYSTRUCT, //some struct I have, details irrelevant 
    ... 
} my_type_enum; 

typedef struct my_var 
{ 
    my_type_enum typetag; 
    unsigned char* data; 
} my_var; 

my_var myrecord[numfields]; 

이 상상, 질문의 목적을 위해 간단합니다. 내 라이브러리는 스키마 파일을 읽고 myrecord의 각 my_var에 대해 태그를 설정하고 데이터에 맞는 양의 공간을 할당합니다.

my_var는 불투명하고 클라이언트 프로그램은 기본적으로 기록에 값을 저장하는 간단한 데이터

void set(my_var* record, size_t field, void * src) 
{ 
    memcpy(record[field].data, src, datatypes[record[field].typetag].size); 
} 

int32_t x = 5; 
set(myrecord, 0, &x); 

를 들어, 사용하고, 유사한 GET()는 물건을 꺼내.

태그가 지정된 my_var 유형은 데이터가 my_var 내에 있으면 유형 검사를 허용하지만 record가 3 개의 INT32를 보유하고 있다고 말하면 당연히 src가 int32_t를 가리키며 mystruct가 아닌지 확인해야합니다 해당 my_var 데이터를 설정하십시오.

분명히 int32_t * 또는 mystruct *가 void *로 변환되기 전에 검사가 wrapping set()에서 수행되어야합니다. typeof() 속임수로 컴파일 타임 검사를 보았습니다. 내가 원하는 것 같은 기분이 들지는 않지만 모든 트릭을 알지 못한다. ...

클라이언트 프로그램 컴파일시 스키마를 읽는 기능을 제공하고 set_CHECKED () wrapper 매크로 누군가가 int32_t를 my_var로 복사하려고 시도 할 때 컴파일러 오류가 발생합니다. GCC 확장이 좋습니다.

답변

0

실제로 '설정'및 '가져 오기'가 정확한 장소 인 것 같습니다 수표. 잘못된 유형의 필드를 액세스하는 치명적인 오류가 있으면 수정은 간단하다 : 유형 불일치 치명적인 오류가 아닌 경우

void set(my_var* record, size_t field, void * src) 
{ 
    if (record[field].typetag != (my_var)src->typetag) { 
     fprintf(stderr, "Type mismatch!\n"); 
     exit(1); 
    } 
    memcpy(record[field].data, src, datatypes[record[field].typetag].size); 
} 

, 당신은 세트와 GET 반환 및 오류 코드를 확인해야합니다 전화 사이트에서 올바르게 처리하십시오.

참고로 C에서는 코드가 으로 컴파일 될 때까지 정보가 없어졌습니다. 'typetag'필드는 필드 유형을 알아야하는 유일한 방법입니다.

물론 라이브러리를 다시 컴파일하지 않고 스키마를 변경할 필요가없는 경우이 스키마에서 C 코드를 생성 해보십시오. 그러면 컴파일 타임에 컴파일러의 유형 검사를 사용할 수 있습니다. 또한

(:없는 큰 문제는, 그러나 my_var.data *이 무효의 *가 아닌 문자해야 이 코드의 정확성을 변경하지 않고 무효가 * 독자 (및 디버거를 알려줍니다) 그. 형식을 알 수 없습니다.)

+0

좀 더 명확하게 편집 하겠지만 src 인수는 저장할 일반 데이터 형식에 대한 포인터입니다. 'int32_t x = 5;' 'set (myrecord, 0, &x);) 'src-> typetag'을 사용할 수 없습니다. –