2013-04-10 2 views
5

임베디드 대상에서 C를 프로그래밍 중입니다. 복잡성과 테스트 가능성 문제가 증가함에 따라 모듈성이 필수적입니다.임베디드 C 프로그래밍 백그라운드에서 모듈로 변수를 전달하는 효율성

한 눈에 프로그램은 제어 루프입니다. 내부 하드웨어를 사용하여 물리적 입력을 읽고 계산을 적용하고 계산 된 출력을 적용합니다. 그러나 컨트롤은 매우 정교하며 많은 내부 상태와 변수가 있습니다.

이 컨트롤은 다른 상태의 기능을 묶어 여러 모듈로 나뉩니다. 일반적인 작업/계산은 별도의 모듈로 제공되며 자신을 DRY 상태로 유지하기 위해 여러 모듈에서 호출됩니다. 전체 프로젝트에서 enum과 형식 일관성을 위해 최상위 .H 파일이 사용됩니다 (상속과 같은 OO 전략은 내 프레임 워크에서 옵션이 아닙니다. 관련이 있습니다).

내 문제는 모듈간에 변수를 전달하는 방법을 결정할 때 발생합니다.

내 초기 접근 방식은 다음과 같습니다

mymodule.H: 

struct Inputs{ 
    int input1; 
    ... 
    int inputN; 
} 

struct Outputs{ 
    int output1; 
    ... 
    int outputN; 
} 

void mymodule(Inputs in,Outputs* out); 

그리고 주요 기능 (또는이 모듈을 호출 모듈)에

는 "입력"을 만들어 "출력"형 구조체가 있습니다.

그런 다음 변수가 Inputs 구조체에 복사되고 함수가 호출되어 (Outputs 구조체 참조) 완료되면이 구조체의 내용이 추후 계산에 사용됩니다.

그러나 각 모듈은 호출 모듈에서 InputType 및 OutputType의 인스턴스를 생성해야하기 때문에 메모리 사용 공간이 커집니다. 그것은 내 의견으로는 훌륭한 해결책이 아닙니다. 동적 할당은 내 프로젝트에서 허용되지 않습니다.

좋은 해결책을 얻으려면 몇 가지 가이드 라인 및/또는 다른 아이디어를 제공해 주시겠습니까?

감사합니다. 솔루션의 추가

는 포인터로 InputStruct을 통과 할 수 있지만,이 모듈에 효과적입니다 입력으로, 어떻게 그들이 코드에 따라 수정되지 않도록 보장 할 수? 그런데 라이트

이 발생하는 문제는 모든 모듈은 동일한 변수를 수신하고 있다는 사실이다 제공되지 않음 상속 메커니즘 (이 C이기 때문에), 각 모듈의 구조가 갖는 함께 적절한 값을로드하십시오. 꽤 ... 난독 화하고

+1

'Inputs' 구조체도 포인터로 전달되어야합니다. – mah

+0

'동적 메모리'를 사용할 수없는 이유는 무엇입니까? 어떻게 복잡한 프로젝트를 완성 할 수 있습니까? –

+0

@ bash.d 분열을 일으킬만한 메모리가 너무 적습니까? –

답변

5

함수에 매개 변수를 전달하거나 함수에서 매개 변수를 전달할 때 많은 메모리 사용 공간을 사용할 필요가 없습니다. 핵심은 참조로 매개 변수를 전달하고 입력이 수정되지 않도록 const 키워드를 사용하는 것입니다.

int strcpy(char *destination, const char *source); 

되는 소스 및 목적지 문자 버퍼 만 포인터가있는 버퍼없는 사본을 전달하지만, const 키워드의 내용을 수정의 strcpy()을 방지한다 : 잘 알려진 예는 소스 버퍼

모든 수단 입력이 수정되지 않도록 보장하기 위해 const 키워드를 사용하는 대신, 다시 함수에 구조체에 대한 포인터를 전달하여 각 통과하면 개별적으로 다음 비현실적 많은 매개 변수가있는 경우 :

int myFunc(struct myFuncOut *outputs, const struct myFuncIn *inputs); 

을 struct가 참조로 전달되기 때문에 myFunc()는 호출 함수에서 사용하는 것과 동일한 메모리에서 작동하지만 (const 키워드 덕분에 inputs이 가리키는 메모리에 쓸 수 없으므로) 메모리 오버 헤드가 함수에 전달하는 것은 일반적인 임베디드 시스템에서 4 바이트 인 포인터의 것만이며 오버런이 없습니다. ead. 한 함수의 출력을 다른 함수에 입력으로 전달 될 필요가 있지만, 매개 변수 목록이 동일하지 않은 것을 두 번째 암시 문제에 관해서는


, 당신이 사본이 아닌 다른 할 수있는 정도가되지 않을 수도 있습니다 하나의 구조체에서 다른 구조체로. 운이 좋으면 다음과 같이 할 수 있습니다.

struct myFunc1Out 
{ 
    int common1; 
    int common2; 
    int common3; 
}; 
struct myFunc2In 
{ 
    int common1; 
    int common2; 
    int common3; 
    int special1; 
    int special2; 
} 

struct myFunc2In data; 

myFunc1((struct myFunc1Out *)(*data), *inputs); 
data.special1 = 1; 
data.special2 = 2; 
myFunc2(*outputs, *data); 

여기에 무슨 일이 일어나고 있니? struct myFunc2In의 첫 번째 부분은 struct myFunc1Out과 동일하므로 이전을 후자로 캐스트 할 수 있으며 추가 필드는 무시됩니다. 당신은 (아주) 가난한 사람의 다형성이라고 생각할 수 있습니다.

또 다른 매개 변수에 대한 두 번째 구조체와 함께 구조체 myFunc1Out을 두 번째 함수에 전달하는 것이 덜 분명합니다. 추가 메모리 비용은 하나의 포인터입니다. 아마도 구조체로 표현되는 논리적 그룹으로 데이터를 구성 할 수 있습니다. 구조체가 너무 많지 않아도 구조체의 나머지 부분이 항상 필요하지 않은 필드를 포함하지는 않습니다.


그러나 덧글 중 하나는 구조체 정의에 실행 파일에 메모리 오버 헤드가 있다고 예상하는 것 같습니다. 이것은 사실이 아닙니다. 구조체의 인스턴스이 할당 된 경우에만 메모리가 사용됩니다.

+0

_const 구조체 * _는 ** 포인터 **가 포인터가 가리키는 구조체가 아니라 상수로 유지된다는 것을 의미합니까? – Manex

+0

좋아, 그냥 체크 아웃, 작동합니다. – Manex

+0

@Manex : 아니요, 상수 포인터는'struct * const'로 선언 될 것입니다. 개인적으로, 포인터 - 상수 - 구조체 선언을 위해, 나는'struct const *'를 선호한다. 그것은'const struct *'와 동일하지만, 다른 구문'const'와 구문 적으로 일치합니다. –

1

module.c :

module.h에
#include "module.h" 

struct Inputs *getInput() { 
    static struct Inputs inputs; 
    return &inputs; 
} 

struct Outputs *getOutput() { 
    static struct Outputs outputs; 
    return &outputs; 
} 

struct Outputs *mymodule() { 
    struct Outputs *o = getOutput(); 
    struct Inputs *i = getInput(); 
    o->output[0] = i->input[0]; 
    return o; 
} 

:

#define N 10 

struct Inputs { 
    int input[N]; 
}; 

struct Outputs { 
    int output[N]; 
}; 


struct Inputs *getInputs(); 
struct Inputs *getOutputs(); 
void mymodule(); 
0

하나의 가능성이 처리기를 사용하여 다음 세터/게터 기능 뒤에 변수를 숨기고하는 것입니다 모듈에서 해당 기능의 가시성을 제어합니다.

iovars.C :

/* iovars.c */ 

static int s_input1; 
static int s_input2; 
static int s_output1; 
static int s_output2; 

int GetIn1(void) { return s_input1; } 
int GetIn2(void) { return s_input2; } 
void SetIn1(int value) { s_input1 = value; } 
void SetIn2(int value) { s_input2 = value; } 
int GetOut1(void) { return s_output1; } 
int GetOut2(void) { return s_output2; } 
void SetOut1(int value) { s_output1 = value; } 
void SetOut2(int value) { s_ouput2 = value; } 

iovars.h : 조금 지루하지만 당신은 지금 당신의 모듈 변수별로 변수에 대한 가시성과 쓸수을 제어 할 수 있었다

/* iovars.h */ 

#ifdef USING_IN1_READONLY || USING_IN1_READWRITE 
int GetIn1(void); 
#ifdef USING_IN1_READWRITE 
void SetIn1(int value); 
#endif 
#endif 

#ifdef USING_IN2_READONLY || USING_IN2_READWRITE 
int GetIn2(void); 
#ifdef USING_IN2_READWRITE 
void SetIn2(int value); 
#endif 
#endif 

#ifdef USING_OUT1_READONLY || USING_OUT1_READWRITE 
int GetOut1(void); 
#ifdef USING_OUT1_READWRITE 
void SetOut1(int value); 
#endif 
#endif 

#ifdef USING_OUT2_READONLY || USING_OUT2_READWRITE 
int GetOut2(void); 
#ifdef USING_OUT2_READWRITE 
void SetOut2(int value); 
#endif 
#endif 

OK :

/* moduleA.c */ 

#define USING_IN1_READONLY 
#define USING_OUT1_READWRITE 
#include "iovars.h" 

/* code in this module can only see functions to read input 1 
    and to read or write output 1 */ 

BTW이 답변은 this question에 대한 응답을 기반으로하며 모든 기능을 인라인으로 가져 오는 것에 대한 일부 토론도 포함되어 있습니다.