it-source

내장된 C 코드의 유지보수성을 위해 #c 소스 파일을 #포함해도 괜찮습니까?

criticalcode 2023. 9. 23. 22:47
반응형

내장된 C 코드의 유지보수성을 위해 #c 소스 파일을 #포함해도 괜찮습니까?

는 C C 는 를 ..c다른 소스 파일은 나쁜 관행으로 간주되지만, 유지보수에 도움이 될 수도 있다고 생각하는 상황이 있습니다.

요소를 큰 합니다를 합니다.#define지수를 유지하기 위해서 입니다.

#define TOTO_IND 0 
#define TITI_IND 1 
…
#define TATA_IND 50

static const MyElements elems [] = {
    {"TOTO", 18, "French"},
    {"TITI", 27, "English"},
    ...,
    {"TATA", 45, "Spanish"}
}

.#define구조 선언이 동기화된 것입니다., 다를 .#define따라서.

오류가 발생하기 쉽고 별로 마음에 들지 않습니다. 하지만 성능을 고려할 때 더 나은 해결책을 찾지 못했습니다.

어쨌든 이 파일에는 이 구조를 다루기 위한 많은 기능들도 포함되어 있습니다.또한 코드 분리를 유지하고 글로벌 변수를 피하고 싶습니다.

을 "더 가능성이 정의를 단일 을 "" , "를" 로 것에 생각하고 있었습니다..c이 구조만 포함하는 소스 파일입니다.이 파일은 "위험한 주의 파일"이며 실제 "정상적으로 작동하는" 파일에 포함됩니다.

그것에 대해 어떻게 생각하십니까?입니까를 입니까?.c소스 파일?더 잘 수 있는 이 또 요?제 구조물을 더 잘 다룰 수 있는 다른 방법이 있을까요?

하여 할 수 .elems[]각 인덱스 식별자(또는 매크로)의 명시적 값을 알 필요가 없습니다.

const MyElements elems[] = {
    [TOTO_IND] = {"TOTO", 18, "French"},
    [TITI_IND] = {"TITI", 27, "English"},
    [TATA_IND] = {"TATA", 45, "Spanish"},
};

배열 요소는 소스 코드에 나타나는 순서를 변경하더라도 동일한 방식으로 초기화됩니다.

const MyElements elems[] = {
    [TITI_IND] = {"TITI", 27, "English"},
    [TATA_IND] = {"TATA", 45, "Spanish"},
    [TOTO_IND] = {"TOTO", 18, "French"},
};

된 경우 (를하여, )를 하여)[][NUM_ELEMS] 더 .), 보다 1 .

를 통해 할 수 .elems.h합니다.합니다.elems별도의 .c 파일에 내용을 배열합니다.

Ian Abbot의 답변과 같이 지정된 이니셜라이저를 사용해야 합니다.

또한 배열 인덱스가 여기와 같이 인접한 경우 대신 열거형을 사용할 수 있습니다.

토토.h

typedef enum
{
  TOTO_IND,
  TITI_IND,
  ...
  TATA_IND,
  TOTO_N    // this is not a data item but the number of items in the enum
} toto_t;

토토

const MyElements elems [] = {
  [TITI_IND] = {"TITI", 27, "English"},
  [TATA_IND] = {"TATA", 45, "Spanish"},
  [TOTO_IND] = {"TOTO", 18, "French"},
};

이제 정적 주장을 통해 어레이 전체의 데이터 무결성을 확인할 수 있습니다.

_Static_assert(sizeof elems/sizeof *elems == TOTO_N, 
               "Mismatch between toto_t and elems is causing rain in Africa");

_Static_assert(sizeof elems/sizeof *elems == TOTO_N, ERR_MSG);

ERR_MSG다음과 같이 정의됩니다.

#define STR(x) STR2(x)
#define STR2(x) #x
#define ERR_MSG "Mismatching toto_t. Holding on line " STR(__LINE__)

다른 답변들은 이미 더 명확한 방법으로 이 문제를 다루었지만, 완전성을 위해, 만약 여러분이 이 길을 기꺼이 따라가서 동료의 분노를 무릅쓸 의지가 있다면, 여기 x-macros 접근법이 있습니다.

X-매크로는 내장된 C 전처리기를 이용한 코드 생성의 한 형태입니다.목표는 몇 가지 단점이 있지만 반복을 최소화하는 것입니다.

  1. 전처리기를 사용하여 숫자와 구조를 생성하는 소스 파일은 익숙하지 않으면 복잡해 보일 수 있습니다.
  2. 소스 파일을 생성하는 외부 빌드 스크립트에 비해 x-macros의 경우 컴파일러 설정을 사용하고 전처리된 파일을 수동으로 확인하지 않는 한 컴파일 중에 생성된 코드가 어떻게 생겼는지 볼 수 없습니다.
  3. 전처리된 출력이 보이지 않기 때문에 외부 스크립트에서 생성된 코드를 사용하는 것과 같은 방식으로 디버거를 사용하여 생성된 코드를 통과할 수 없습니다.

매크로 호출 목록을 별도의 파일에 작성하는 것으로 시작합니다.elements.inc, 이 시점에서 매크로가 실제로 수행하는 작업을 정의하지 않고 다음과 같이 수행합니다.

// elements.inc

// each row passes a set of parameters to the macro,
// although at this point we haven't defined what the
// macro will output

XMACRO(TOTO, 18, French)
XMACRO(TITI, 27, English)
XMACRO(TATA, 45, Spanish)

그런 다음 이 목록을 포함해야 할 때마다 매크로를 정의하여 각 호출을 작성할 구성의 단일 행으로 렌더링하고 일반적으로 이를 연속으로 여러 번 반복합니다.

// concatenate id with "_IND" to create enums, ignore code and description
// (notice how you don't need to use all parameters each time)
// e.g. XMACRO(TOTO, 18, French) => TOTO_IND,
#define XMACRO(id, code, description) id ## _IND,
typedef enum
{
#    include "elements.inc"
     ELEMENTS_COUNT
}
Elements;
#undef XMACRO

// create struct entries
// e.g. XMACRO(TOTO, 18, French) => [TOTO_IND] = { "TOTO", 18, "French" },
#define XMACRO(id, code, description) [id ## _IND] = { #id, code, #description },
const MyElements elems[] = {
{
#    include "elements.inc"
};
#undef XMACRO

이것은 다음과 같은 것으로 전처리됩니다.

typedef enum
{
    TOTO_IND,
    TITI_IND,
    TATA_IND,
    ELEMENTS_COUNT
}
Elements;

const MyElements elems[] = {
{
    [TOTO_IND] = { "TOTO", 18, "French" },
    [TITI_IND] = { "TITI", 27, "English" },
    [TATA_IND] = { "TATA", 45, "Spanish" },
};

분명히 리스트의 잦은 유지보수는 코드 생성이 더 복잡해지는 대신에 더 쉬워집니다.

정의const~하듯이static 것은 큰다의 .MyElements. 이것은 내장된 시스템에서 메모리를 증가시킬 것입니다.static한정자를 제거해야 합니다.

다음은 제안된 해결책입니다.

파일로

#define TOTO_IND 0 
#define TITI_IND 1 
…
#define TATA_IND 50
#define MAX_ELEMS 51

extern const MyElements elems[MAX_ELEMS];

파일로

#include "file.h"
const MyElements elems [MAX_ELEMS] = {
    {"TOTO", 18, "French"},
    {"TITI", 27, "English"},
    ...,
    {"TATA", 45, "Spanish"}
}

#include "file.h"필요한 .c 파일에 저장합니다.

인 질문을 #include.c파일(다른 답변은 더 나은 옵션을 제안합니다. 특히 Groo의 것), 일반적으로 그럴 필요가 없습니다.

의 에 있는 것..c에서 볼 수 할 수 및다를 할 수 .#extern. 예를 들어, 당신은 당신의 테이블을 참조할 수 있습니다.#extern const MyElements elems [];본심으로는.c파일.

또는 정의를 다음과 같이 나타낼 수 있습니다..h파일을 작성하고 그것을 포함합니다.그렇게 하면 원하는 대로 코드를 분리할 수 있습니다.모두 기억하세요.#includedoes는 포함된 파일의 내용을 삽입합니다. 여기서#include문장(statement)은 특정 파일 확장명을 가질 필요가 없습니다..h관례에 의해 사용되며 대부분의 IDE는 자동으로 추가됩니다..c컴파일할 파일 목록에 있는 파일이지만 컴파일러에 관한 한 명명은 임의적입니다.

ReferenceURL : https://stackoverflow.com/questions/52757696/is-it-ok-to-include-c-source-file-for-maintainability-of-embedded-c-code

반응형