나는 당신이 (이상적) 원하는 것은 사전 용의자 :
물론
theMeas[i]["signal_path"] = atoi(&chunk[2]);
, 위의 구문은 C에서 발생하지 않습니다,하지만 여기 정말 중요하지 않아. 문제는 사전 데이터 유형을 구현하는 모든 코드를 작성해야한다는 것이며, 과도하다고 생각합니다. 가지 (
foreach(signal_path, trace_length, sample_rate)
그리고 난 당신이 할 수있는 당신에게 여기있어 :
그래서 나는 당신이 (정말) 원하는 것은 루프에서 사용할 수있는 이름을 가질 수있는 방법 의심)!가장 간단한 방법은 enum
함께 대신 struct
회원의
enum fields {
signal_path,
trace_length,
sample_rate,
END_fields,
UNKNOWN_fields,
BEGIN_fields = 0,
};
, 당신은 배열 사용 인덱스로
int theMeas[size][END_fields];
는 "회원"이 사용
theMeas[i][signal_path];
당신 모든 "회원"을 통해 반복 할 수 있습니다. 다음을 사용할 수 있습니다.
for(enum fields j = BEGIN_fields; j != END_fields; j++)
theMeas[i][j];
당신은 문자 기반의 비교를 얻을 할 때
이 조금 분해 않지만, 우리는 약간의 작업을 수행 할 수 있습니다
theMeas[i][from_abv(chunk)] = atoi(&chunk[2]);
또는 :
const char *to_str(enum fields f)
{
#define FIELD(x) case x: return #x
switch(f)
{
FIELD(signal_path);
FIELD(trace_length);
FIELD(sample_rate);
default: return "<unknown>";
}
#undef FIELD
}
enum fields from_str(const char *c)
{
#define FIELD(x) if(!strcmp(c, #x)) return x
FIELD(signal_path);
FIELD(trace_length);
FIELD(sample_rate);
default: return UNKNOWN_fields;
#undef FIELD
}
enum fields from_abv(char *c)
{
for(enum fields i = BEGIN_fields; i < END_fields; i++)
{
char *field = field_str(i);
if(tolower(c[0]) == field[0] && tolower(c[1]) == strchr(field, '_')[1])
return i;
}
return UNKNOWN_fields;
}
귀하의 if
문 는 대체 될 수있다 더 안전하게 :
enum fields j = from_abv(chunk);
if(j != UNKNOWN_fields) theMeas[i][j] = atoi(&chunk[2]);
else /* erroneous user input */;
어느 정도까지 얻을 수 있습니다.
많은 부분을 자동화하는 매크로 작성을 용이하게하기 위해 의도적으로 명명 체계를 사용했습니다. 의 시도하자
#define member(name, ...) \
enum name { __VA_ARGS__, \
M_END_##name, \
M_UNKNOWN_##name, \
M_BEGIN_##name = 0 }
#define miter(name, var) \
enum name var = M_BEGIN_##name; var != M_END_##name; var++
#define msize(name) M_END_##name
사용법 : 마지막 비트가 그렇게 나쁜 것 같지 않습니다
// define our fields
member(fields, signal_path, trace_length, sample_rate);
// declare object with fields
int theMeas[N][msize(fields)];
for(size_t i = 0; i < N; i++)
// iterate over fields
for(miter(fields, j))
// match against fields
if(j == from_abv(chunk))
theMeas[i][j] = atoi(&chunk[2]);
있다. 여전히 struct
과 비슷한 접근을 theMeas[i][signal_path]
을 통해 허용하지만, "멤버"를 반복 할 수 있으며 매크로 뒤에있는 많은 부분을 숨길 수 있습니다.
to_str
및 from_str
함수는 자동화하기 위해 약간의 매크로 트릭을 사용합니다. 아마도 P99를 살펴 봐야 할 것입니다. from_abv
함수는 다음에 반복 가능한 필드를 만들 때 밑줄이있는 이름을 사용한다는 것을 보장 할 수있는 방법이 없으므로 일반적인 경우에 권장 할만한 기능이 아닙니다. 물론 from_abv
함수를 삭제하고 구성원에게 SP
, TL
및 SR
과 같은 이해하기 어려운 이름을 제공하여 문자열 데이터와 직접 비교할 수 있지만 strcmp
을 memcmp
크기로 변경해야합니다 (sizeof(#x) - 1)
의 인수. 그리고 모든 장소 방금 자동으로 생성 할 수 있습니다 from_str
을 사용하십시오 from_abv
이는.)
그러나, from_abv
정의 어렵지 않다, 당신은 복사하여 붙여 넣기 정직 수 if
블록을 위에 얹어 놓으십시오 - 좀 더 효율적일 것입니다.하지만 "멤버"를 추가하면 함수를 업데이트해야합니다 (작성한대로 추가하면 추가됩니다).
파이썬과 같은 사전을 원하십니까, 아니면 '구조체'에서 명명 된 데이터에 액세스하는 더 쉬운 방법을 원하십니까? 하나는 다른 하나보다 훨씬 더 어렵습니다. –
if 분기를 제거하고 싶습니다. 그래서 청크가 구조체 멤버에 매핑되는 루프에서 하나의 명령문을 사용할 수 있습니다. 파이썬 같은 동적 인 언어에서 나는 theMeas [chunk] = chunk [2]를 할 수있었습니다. –
'chunk'는 "theMeas [i] [chunk]"를 (파이썬에서도) 할 수있는 것처럼 보이지 않습니다. 처음 두 글자를 원하는 회원의 머리 글자로 사용하고 있습니다. 'chunk [0]'과'chunk [1]'만을 사용한다. –