C 구조체의 기본값
데이터 구조는 다음과 같습니다.
struct foo {
int id;
int route;
int backup_route;
int current_route;
}
및 update()라는 함수로 변경을 요구하기 위해 사용됩니다.
update(42, dont_care, dont_care, new_route);
이것은 매우 길기 때문에 구조에 무언가를 추가하면 업데이트하기 위해 모든 콜에 'dont_care'를 추가해야 합니다(...).
대신 구조를 전달하려고 생각하고 있습니다만, 사전에 'dont_care'로 구조를 채우는 것은 단순히 함수 호출로 설명하는 것보다 더 지루합니다.로컬 변수로 선언한 후 dont care 기본값으로 구조체를 만들고 관심 있는 필드를 설정할 수 있습니까?
struct foo bar = { .id = 42, .current_route = new_route };
update(&bar);
표현하고 싶은 정보만 업데이트 기능에 전달하는 가장 우아한 방법은 무엇입니까?
그 외는 모두 디폴트 -1('돈트 케어'의 암호)로 해 주세요.
매크로나 기능(이미 제안된 대로)은 기능하지만(또한 다른 긍정적인 효과(디버깅 후크 등)는 필요 이상으로 복잡합니다.가장 간단하고 가장 우아한 솔루션은 변수 초기화에 사용할 상수를 정의하는 것입니다.
const struct foo FOO_DONT_CARE = { // or maybe FOO_DEFAULT or something
dont_care, dont_care, dont_care, dont_care
};
...
struct foo bar = FOO_DONT_CARE;
bar.id = 42;
bar.current_route = new_route;
update(&bar);
하는 데 드는 오버헤드가 이 코드에서는 어떤 가 있는지 합니다.bar
명시적으로 설정하는 한편, 설정하지 않은 것은 무시합니다.
비밀 특수값을 0으로 변경하여 C의 기본 구조 멤버 시멘틱스를 이용할 수 있습니다.
struct foo bar = { .id = 42, .current_route = new_route };
update(&bar);
그러면 이니셜라이저에서 지정되지 않은 바의 멤버로0이 전달됩니다
또는 기본 초기화를 수행할 매크로를 만들 수 있습니다.
#define FOO_INIT(...) { .id = -1, .current_route = -1, .quux = -1, ## __VA_ARGS__ }
struct foo bar = FOO_INIT( .id = 42, .current_route = new_route );
update(&bar);
<stdarg.h>
함수를 할 수 예: 되지 않은 경우).printf()
하는 함수를 할 속성을 임의 개수의 인수 쌍을 사용하는 함수를 정의합니다.하나는 업데이트할 속성을 지정하고 다른 하나는 값을 지정합니다. '어울리다'를 사용하세요.enum
또는 속성 이름을 지정하는 문자열입니다.
그 대신 프리프로세서 매크로 정의를 사용하는 것을 검토해 주십시오.
#define UPDATE_ID(instance, id) ({ (instance)->id= (id); })
#define UPDATE_ROUTE(instance, route) ({ (instance)->route = (route); })
#define UPDATE_BACKUP_ROUTE(instance, route) ({ (instance)->backup_route = (route); })
#define UPDATE_CURRENT_ROUTE(instance, route) ({ (instance)->current_route = (route); })
(struct foo) 인스턴스가 글로벌한 경우 당연히 파라미터는 필요하지 않습니다.하지만 한 가지 이상의 사례가 있을 거라고 생각합니다.({...) 사용) block은 GCC에 적용되는 GNU-ism으로, 행을 블록으로 묶는 좋은 (안전한) 방법입니다.나중에 범위 검증 확인 등 매크로에 추가해야 하는 경우 if/else 문 등의 파손을 걱정할 필요가 없습니다.
당신이 제시한 요건에 따라 저는 이렇게 하겠습니다.이런 상황이 제가 python을 많이 사용하기 시작한 이유 중 하나입니다.기본 파라미터 등의 조작은 C보다 훨씬 간단합니다.(그건 python 플러그라고 생각합니다.죄송합니다;-)
패턴 고브젝트에서는 바리어스 함수와 각 속성의 열거값이 사용됩니다.인터페이스는 다음과 같습니다.
update (ID, 1,
BACKUP_ROUTE, 4,
-1); /* -1 terminates the parameter list */
varargs 함수는 간단하게 기술할 수 있습니다.http://www.eskimo.com/ ~scs/cclass/int/sx11b.http://http://www.eskimo.com/ 를 참조해 주세요.키 -> 값의 쌍을 대조하고 적절한 구조 속성을 설정하기만 하면 됩니다.
한 것은, 「」에 되어 있기 때문에, 이 입니다.update()
이 함수에 대해서는 구조를 전혀 사용하지 마십시오. 이 구조 뒤에 있는 당신의 의도를 혼란스럽게 할 뿐입니다.이러한 필드를 변경 및 업데이트하는 이유를 재고하고 이 "작은" 변경에 대해 별도의 기능 또는 매크로를 정의해야 할 수도 있습니다.
예.
#define set_current_route(id, route) update(id, dont_care, dont_care, route)
#define set_route(id, route) update(id, dont_care, route, dont_care)
#define set_backup_route(id, route) update(id, route, dont_care, dont_care)
또는 모든 변경 사례에 대한 함수를 작성하는 것이 좋습니다.이미 모든 속성을 동시에 변경하는 것은 아니기 때문에 한 번에 하나의 속성만 변경할 수 있습니다.이를 통해 가독성이 향상될 뿐만 아니라 다양한 사례를 처리할 수 있습니다.예를 들어 현재 경로만 변경되었음을 알고 있기 때문에 모든 "dont_care"를 확인할 필요는 없습니다.
예를 들어 다음과 같습니다.
struct foo bar;
update(init_id(42, init_dont_care(&bar)));
포함:
struct foo* init_dont_care(struct foo* bar) {
bar->id = dont_care;
bar->route = dont_care;
bar->backup_route = dont_care;
bar->current_route = dont_care;
return bar;
}
또, 다음과 같이 합니다.
struct foo* init_id(int id, struct foo* bar) {
bar->id = id;
return bar;
}
그리고 이에 대응:
struct foo* init_route(int route, struct foo* bar);
struct foo* init_backup_route(int backup_route, struct foo* bar);
struct foo* init_current_route(int current_route, struct foo* bar);
C++에서는 비슷한 패턴의 이름이 기억나지 않습니다.
구조에 익숙치 않아서 키워드를 몇 개 놓쳤나 봐요그러나 기본값이 초기화된 글로벌 구조에서 시작하여 로컬 변수에 복사한 후 수정하는 것은 어떻습니까?
이니셜라이저:
void init_struct( structType * s )
{
memcopy(s,&defaultValues,sizeof(structType));
}
그 후, 사용하고 싶은 경우:
structType foo;
init_struct( &foo ); // get defaults
foo.fieldICareAbout = 1; // modify fields
update( &foo ); // pass to function
X-Macro로 문제를 해결할 수 있습니다.
구조 정의를 다음과 같이 변경합니다.
#define LIST_OF_foo_MEMBERS \
X(int,id) \
X(int,route) \
X(int,backup_route) \
X(int,current_route)
#define X(type,name) type name;
struct foo {
LIST_OF_foo_MEMBERS
};
#undef X
모든 를 '유연함수'로 하는 ''를 쉽게 할 수 .dont_care
.
#define X(type,name) in->name = dont_care;
void setFooToDontCare(struct foo* in) {
LIST_OF_foo_MEMBERS
}
#undef X
여기서 설명한 후에는 다음과 같은 방법으로 기본값을 정의할 수도 있습니다.
#define X(name) dont_care,
const struct foo foo_DONT_CARE = { LIST_OF_STRUCT_MEMBERS_foo };
#undef X
그 의미는 다음과 같습니다.
const struct foo foo_DONT_CARE = {dont_care, dont_care, dont_care, dont_care,};
또한 hlovdal 답변과 같이 사용합니다.여기에서는 유지보수가 용이하다는 장점이 있습니다.즉, 구조체 멤버의 수를 변경하면 자동으로 갱신됩니다.마지막 '스플리어스' 콤마는 허용됩니다.
나는 이 문제를 해결해야 할 때 X-Macros의 개념을 처음 배웠다.
구조물에 추가할 새 필드에 매우 유연합니다.서로 다른 데이터 유형을 사용하는 경우 서로 다른 데이터 유형을 정의할 수 있습니다.dont_care
데이터 유형에 따라 값이 달라집니다.여기서 두 번째 예의 값을 인쇄하는 데 사용되는 함수에서 영감을 얻을 수 있습니다.
모두 괜찮으시다면int
데이터 유형을 생략할 수 있습니다.LIST_OF_foo_MEMBERS
구조 정의의 X 함수를 간단히 바꿔서#define X(name) int name;
가장 우아한 방법은 구조 필드를 직접 업데이트하는 것입니다.update()
기능 - 하지만 질문에는 나타나지 않는 적절한 이유가 있을 수 있습니다.
struct foo* bar = get_foo_ptr();
foo_ref.id = 42;
foo_ref.current_route = new_route;
또는 Puku가 제안한 대로 구조의 각 필드에 대해 별도의 액세스 기능을 만들 수 있습니다.
그렇지 않으면 구조 필드의 값 '0'을 '업데이트 안 함' 플래그로 처리하는 것이 가장 좋습니다.따라서 펑시톤을 생성하여 제로아웃된 구조를 반환하고 이를 사용하여 업데이트를 수행합니다.
struct foo empty_foo(void)
{
struct foo bar;
bzero(&bar, sizeof (struct bar));
return bar;
}
struct foo bar = empty_foo();
bar.id=42;
bar.current_route = new_route;
update(&bar);
단, 0이 구조체의 필드에 유효한 값인 경우 이 값은 그다지 실현 가능하지 않을 수 있습니다.
언급URL : https://stackoverflow.com/questions/749180/default-values-in-a-c-struct
'programing' 카테고리의 다른 글
형식 스크립트가 있는 Vue2, 유형에 속성이 없습니다. (0) | 2022.08.30 |
---|---|
구조 내 구성원의 순서가 중요합니까? (0) | 2022.08.30 |
Firebase SnapShot.val()이 vuex의 데이터에 액세스하려고 할 때 null을 반환함 (0) | 2022.08.30 |
String #equals 메서드와 String #contentEquals 메서드의 차이 (0) | 2022.08.30 |
off_t, size_t 등의 인쇄 방법은 무엇입니까? (0) | 2022.08.30 |