끄적끄적

반응형

구조체를 리턴할 때 어떻게 사용하는게 메모리 효율과 데이터값을 보전하면서 사용해야하는지 모르겠습니다. 



기존방법 


구조체 인스턴스 변수를 extern으로 선언하여. 함수 호출 시 그대로 데이터 값과 구조체를 사용하여 리턴한다.(리터할필요도 없을듯) 



->문제는 extern으로 사용하기때문에 구조체크기가 커질경우 메모리를 아무래도 많이 차지하고, 함수호출시 구조체가 복사되어 


느려진다는 단점이 있습니다. 


==> extern 키워드를 뭔가 잘못 이해하고 계신게 아닌가 싶습니다. 전역변수를 얘기하신 것 

같은데.. extern 키워드는 A라는 파일에 선언된 전역변수를 B라는 파일에서 사용하고 싶을 때 이 변수는 B 파일 외부에 정의된 변수라는 의미로 사용되는 것입니다. 




두번째 방법 


구조체 주소값을 함수호출시 인수로 사용하고 포인터 변수로 받아 사용한다.. 


->주소값을 클론구조체에 전달하여 사용하므로 결국 메모리 효율면에선 떨어진다. 


==> 구조체 주소값이라면 이미 호출부 쪽에서 구조체가 선언되어 있고 그것의 주소를 넘긴다는 

뜻 같은데 그것을 왜 다시 포인터 변수로 받아서 사용한다는 것인지 잘 이해가 되질 않네요..ㅡ.ㅡa 

위와 같이 전달할 경우, 해당 함수에서 인수로 전달된 포인터를 통해 구조체를 다루기 때문에 

호출부의 구조체가 수정된 효과를 얻을 수 있죠.(이것이 바로 call by reference) 




세번째 방법 


구조체 포인터 변수를 사용하여 주소값만 함수 인수로 전달하고 함수내부에서 지역포인터변수로 구조체를 malloc()하여 


사용하고 함수포인터를 이용하여 리턴한다. 


-> 이방법이 제일 좋은 방법같긴 한데.... 포인터변수를 이용하여 주소값을 전달받았을때 구조체 데이터값들도 포함되어있기때문에 


malloc()한 뒤 그 구조체 멤버데이터값들도 또다시 대입해줘야 하는거아닌가여? 



==> 대충 무슨 뜻인지는 이해하겠습니다만 함수포인터를 어떻게 이용한다는 것인지..? 




분할컴파일환경에서. 데이터가 들어있는 구조체를 다른파일에 전달하여 프로세싱을 거친후 새롭게 데이터가 채워진 구조체를 


다시 리턴해야 하는 과정에서 어떻게 사용해야 제일 좋은 방법일까여? (구조체가 크기가 크다는 가정) 




조언좀 부탁드립니다. 






위에 얘기 하신걸 정리해보면 대충 아래 세가지 방법이 나옵니다. 


1. 전역변수로 선언하는 방법 

2. 함수의 리턴값으로 구조체를 전달하는 방법 

3. 함수의 인자로 구조체의 포인터를 전달하는 방법 



먼저 첫번째 방법은 가장 비추입니다. 

전역변수로 쓰는 방법은 문제가 있는 것이 전역변수로 구조체를 선언해 버리면 

아래 얘기 하신대로 프로그램에서 그 구조체를 더 이상 사용하지 않더라도 계속 

메모리 상에 존재하여 메모리의 낭비를 가져올 수 있다는 것이죠. 구조체가 커 

진다면 말할 것도 없고요. 

하지만 더 큰 문제는 해당 전역변수와 이를 다루는 함수와의 결합도를 증가시켜 

프로그램의 유지보수성을 저해시킨다는 것이 아닐까 싶습니다. 

동일한 타입의 구조체 변수가 두개인 경우 각 변수를 위한 동일한 기능을 하는 

다른 함수들이 필요할 테니까요. 이를테면.. 


// global variables 

struct Person g_Tom; 

struct Person g_Mary; 



void SetAgeOfTom() 

g_Tom.age = 10; 


void SetAgeOfMary() 

g_Tom.age = 20; 


이런 것이죠.. 뭐 어디까지나 극단적인 예일 뿐입니다. 




가장 직관적이고 손쉬운 방법은 뭐니뭐니해도 구조체를 함수의 리턴값으로 사용 

하는 것입니다. 


struct Person GetPerson( /* ... */ ) 

struct Person someone; 


// 구조체를 채움 


return someone; 


int main() 

struct Person Tom; 


Tom = GetPerson( /* .. */ ); 


// ... 


위와 같이 사용할 경우, someone이 Tom으로 복사되는 비용과 함수 리턴과정에서 

생기는 임시 객체 생성 비용이 문제라면 문제 일 수 있겠죠. 



그래서 추천하는 방법은 호출부에서 선언된 변수의 주소를 전달하는 방식입니다. 

call by reference라고도 불리우죠. 


void SetPerson( struct Person * pSomeone ) 

pSomeone->age = 10; 

//.. 등등.. 구조체를 채움 


int main() 

struct Person Tom; 


SetPerson( &Tom ); 

//.. 


이렇게 하면 SetPerson()에서 변경된 값이 main에도 적용이 됩니다. 이렇게 사용 

할 경우 구조체가 커진다고 하더라도 구조체 전달을 위한 비용은 증가하지 않죠. 


호출부에서 변수를 선언하지 않고 호출하는 함수 안에서 동적으로 메모리를 할당 

받아 그것에 대한 포인터를 호출부로 전달받는 방법도 생각해 볼 수 있는데 이런 

경우에는 호출부에서 메모리 해제를 담당해야하기 때문에 주위를 기울여 프로그 

램을 짜지 않으면 메모리 누수의 위험이 생길 수 있습니다. 


struct Person * AllocPerson() 

struct Person * pSomeone = malloc( sizeof( struct Person ) ); 

// 구조체 채움 

return pSomeone; 


int main() 

struct Person * pTom = AllocPerson(); 

// ... 

free( pTom ); // 할당한 메모리 해제 잊지 맙시다! 

return 0; 



마지막 질문에 대한 것은.. 만약 저라면.. 

일단 구조체의 크기가 큰 경우라면 구조체 직접 리턴하는 방식은 비추이고, 

call by reference로 전달하던가 동적할당해서 사용하는 방식에서 고르게 되는데 

꼭 동적할당 해야할 필요가 있는 경우가 아니라면 구조체의 주소를 전달하는 방식을 

사용할 것 같네요. 

반응형
Please Enable JavaScript!
Mohon Aktifkan Javascript![ Enable JavaScript ]