문제

나는 매우 큰 것을 가지고 있습니다 struct 기존 프로그램에서. 이 구조물에는 많은 비트 필드가 포함되어 있습니다.

나는 그것의 일부를 저장하고 싶습니다 (예 : 150 중 10 개의 필드).

서브 클래스를 저장하는 데 사용하는 예제 코드는 다음과 같습니다.

typedef struct {int a;int b;char c} bigstruct;
typedef struct {int a;char c;} smallstruct;
void substruct(smallstruct *s,bigstruct *b) {
    s->a = b->a;
    s->c = b->c;
}
int save_struct(bigstruct *bs) {
    smallstruct s;
    substruct(&s,bs);
    save_struct(s);
}

또한 매번 변경하고 싶기 때문에 어느 부분을 선택하는 것이 너무 번거롭지 않기를 바랍니다. 내가 전에 제시 한 순진한 접근법은 매우 연약하고 인재 할 수 없습니다. 최대 20 개의 다른 필드를 확장 할 때는 모두에서 필드를 변경해야합니다. smallstruct, 그리고, 그리고 substruct 기능.

나는 두 가지 더 나은 접근법을 생각했다. 불행히도 둘 다 외부를 사용해야합니다 내 구조를 구문 분석하는 도구처럼.

첫 번째 접근법은 자동으로 생성하는 것입니다 substruct 기능. 나는 단지 구조물을 설정할 것이다 smallstruct, 그것을 구문 분석하고 생성하는 프로그램이 있습니다. substruct 필드에 따라 기능합니다 smallstruct.

두 번째 접근법은 (C Parser와 함께)에 대한 메타 정보를 구축하는 것입니다. bigstruct, 그런 다음 구조물의 특정 필드에 액세스 할 수있는 라이브러리를 작성하십시오. 그것은 Java의 클래스 반사의 임시 구현과 같습니다.

예를 들어, 구조물에 대한 구조 조정이 없다고 가정합니다

struct st {
    int a;
    char c1:5;
    char c2:3;
    long d;
}

다음 메타 정보를 생성하겠습니다.

int field2distance[] = {0,sizeof(int),sizeof(int),sizeof(int)+sizeof(char)}
int field2size[] = {sizeof(int),1,1,sizeof(long)}
int field2bitmask[] =  {0,0x1F,0xE0,0};
char *fieldNames[] = {"a","c1","c2","d"};

나는 얻을 것이다 ith 이 기능의 필드 :

long getFieldData(void *strct,int i) {
    int distance = field2distance[i];
    int size = field2size[i];
    int bitmask = field2bitmask[i];
    void *ptr = ((char *)strct + distance);
    long result;
    switch (size) {
        case 1: //char
             result = *(char*)ptr;
             break;
        case 2: //short
             result = *(short*)ptr;
        ...
    }
    if (bitmask == 0) return result;
    return (result & bitmask) >> num_of_trailing_zeros(bitmask);
 }

두 방법 모두 추가 작업이 필요하지만 파서가 메이크 파일에 있으면 하위 구조를 바꾸는 것은 산들 바람입니다.

그러나 외부 의존성 없이도 그렇게하고 싶습니다.

누구든지 더 나은 아이디어가 있습니까? 내 아이디어가 좋은 곳은 인터넷에서 내 아이디어를 구현할 수있는 일이 있습니까?

도움이 되었습니까?

해결책

필드의 순서를 변경하는 것이 문제가되지 않으면 소규모 스트럭 필드가 함께있는 방식으로 Bigstruct 필드를 재정렬 할 수 있으며 단순히 단순히 서로 캐스팅하는 문제 (아마도 오프셋을 추가 할 수 있음). . 같은 것 :

typedef struct {int a;char c;int b;} bigstruct;
typedef struct {int a;char c;} smallstruct;

int save_struct(bigstruct *bs) {
    save_struct((smallstruct *)bs);
}

다른 팁

설명을 통해 원래 구조에 액세스하고 수정할 수있는 것처럼 보입니다. 나는 당신이 당신의 하위 구조를 완전한 유형으로 리팩토링 한 다음 (당신의 예에서와 같이) 그 구조를 큰 구조의 필드로 만들어 원래 구조의 모든 필드를 작은 구조로 캡슐화하는 것이 좋습니다.

작은 예에서 확장 :

typedef struct 
{
  int a;
  char c;
} smallstruct;

typedef struct 
{
  int b;
  smallstruct mysub;
} bigstruct;

소규모 스트럽 정보에 액세스하는 것은 다음과 같이 수행됩니다.

/* stack-based allocation */
bigstruct mybig;
mybig.mysub.a = 1;
mybig.mysub.c = '1';
mybig.b = 2;

/* heap-based allocation */
bigstruct * mybig = (bigstruct *)malloc(sizeof(bigstruct));
mybig->mysub.a = 1;
mybig->mysub.c = '1';
mybig->b = 2;

그러나 당신은 또한 포인터를 작은 구조물로 전달할 수도 있습니다.

void dosomething(smallstruct * small)
{ 
  small->a = 3;
  small->c = '3';
}

/* stack based */    
dosomething(&(mybig.mysub));

/* heap based */    
dosomething(&((*mybig).mysub));

이익:

  • 매크로가 없습니다
  • 외부 의존성이 없습니다
  • 메모리 주문 캐스팅 해킹이 없습니다
  • 깨끗하고 읽기 쉬운 코드.

매크로는 당신의 친구입니다.

한 가지 해결책은 큰 구조물을 자체 파일로 옮기고 매크로 파티를 갖는 것입니다.

구조를 정상적으로 정의하는 대신 시작_structure, end_structure, normal_field, subset_field와 같은 매크로를 선택하십시오.

그런 다음 파일을 몇 번 포함시켜 각 패스에 대한 해당 구조를 재정의 할 수 있습니다. 첫 번째는 정의를 정상 구조로 바꾸고, 두 유형의 필드는 정상적으로 출력됩니다. 두 번째는 Normal_field가 아무것도없고 서브 세트를 생성 할 것입니다. 세 번째는 서브 세트 필드를 복사하기위한 적절한 코드를 만듭니다.

구조의 단일 정의로 끝나면 서브 세트에 어떤 필드를 제어하고 적절한 코드를 자동으로 생성 할 수 있습니다.

메타 데이터를 얻는 데 도움을주기 위해 오프셋 () 매크로를 참조 할 수 있습니다.

나는이 접근법을 취할 것을 제안한다 :

  1. 큰 구조를 쓴 사람을 저주하십시오. 부두 인형을 얻고 재미있게 보내십시오.
  2. 어떻게 든 필요한 큰 구조의 각 필드를 표시하십시오 (매크로 또는 댓글 또는 무엇이든)
  3. 헤더 파일을 읽고 표시된 필드를 추출하는 작은 도구를 작성하십시오. 주석을 사용하는 경우 각 필드에 우선 순위 또는 정렬 할 수있는 무언가를 줄 수 있습니다.
  4. 하위 구조에 대한 새 헤더 파일을 작성하십시오 (고정 헤더 및 바닥 글 사용).
  5. 함수가 포함 된 새 C 파일을 작성하십시오 createSubStruct 큰 구조물에 대한 포인터를 취하고 포인터를 하위 구조로 반환합니다.
  6. 함수에서 수집 된 필드를 통한 루프 및 방출 ss.field = bs.field (즉, 필드를 하나씩 복사하십시오).
  7. Makefile에 작은 도구를 추가하고 새 헤더 및 C 소스 파일을 빌드에 추가하십시오.

사용하는 것이 좋습니다 gawk, 도구로서, 당신이 편한 스크립팅 언어; 건축하는 데 30 분이 걸립니다.

편집] 당신이 정말로 반성을 시도하고 싶다면 (내가 제안하는 것; 그것은 많은 일이 C에서 그 일을하게 될 것입니다), offsetof() 매크로는 당신의 친구입니다. 이 매크로는 필드의 오프셋을 구조로 반환합니다 (가장 자주 ~ 아니다 이전 필드의 크기의 합). 보다 이 기사.

edit2] 자신의 파서를 쓰지 마십시오. 자신의 파서를 올바르게 얻으려면 몇 달이 걸립니다. 나는 내 인생에서 많은 파서를 썼기 때문에 알고 있습니다. 대신 복사 해야하는 원래 헤더 파일의 일부를 표시 한 다음, 알고있는 하나의 구문 분석기 (C 컴파일러 중 하나)에 의존하십시오. 이 작업을 만드는 방법은 다음과 같습니다.

struct big_struct {
    /**BEGIN_COPY*/
    int i;
    int j : 3;
    int k : 2;
    char * str;
    /**END_COPY*/
    ...
    struct x y; /**COPY_STRUCT*/
}

도구를 복사하십시오 /**BEGIN_COPY*/ 그리고 /**END_COPY*/.

특별한 주석을 사용하십시오 /**COPY_STRUCT*/ 도구를 생성하도록 지시합니다 memcpy() 과제 등 대신

이것은 몇 시간 안에 작성 및 디버깅 할 수 있습니다. 기능없이 C에 대한 구문 분석기를 설정하는 데 시간이 오래 걸릴 것입니다. 즉, 유효한 C를 읽을 수있는 것이 있지만 C를 이해하는 구식의 일부와 데이터에 유용한 부분을 작성해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top