C 언어에서 구조체를 값으로 함수에 전달하면 구조체의 전체 사본이 임시 메모리(일반적으로 함수의 스택)에 생성됩니다. 이는 함수 내부에서의 변경 사항이 함수 외부의 원래 구조체에 전혀 영향을 미치지 않음을 의미합니다.
큰 구조체를 값으로 전달할 경우 모든 구조체 멤버를 복사해야 하므로 시간과 메모리의 비용이 발생합니다. 따라서 표준 관행은 구조체에 대한 포인터 전달입니다:
#include <stdio.h> struct Data { int arr[1000]; int flag; }; void modify_by_value(struct Data d) { d.flag = 10; // 로컬 사본만 수정됨 } void modify_by_pointer(struct Data *d) { d->flag = 20; // 원본 수정됨 } int main() { struct Data data = { {0}, 0 }; modify_by_value(data); // data.flag == 0 modify_by_pointer(&data); // data.flag == 20 return 0; }
포인터로 전달하는 장점:
값으로 전달하는 단점:
함수가 구조체를 값으로 반환하면 어떻게 됩니까? 어떤 위험이 있습니까?
답변:
C에서는 함수에서 구조체를 값으로 반환할 수 있습니다, 예를 들어:
struct Point { int x, y; }; struct Point make_point(int x, int y) { struct Point p = {x, y}; return p; // 사본이 반환됨 }
주요 위험은 성능입니다: 구조체의 사본이 생성되어 반환됩니다. 게다가, 잘못된 방식으로 지역 변수의 주소를 반환하면 구조체가 유효하지 않은 메모리를 가리킬 수 있습니다:
struct Point* bad() { struct Point p = {1, 2}; return &p; // 오류: 지역 변수의 주소 반환 }
이야기
스택이 작은 임베디드 장치에서 개발자는 큰 구조체(1 KB)를 값으로 전달하여 스택 오버플로우 및 임의 시스템 중단을 초래했습니다. 조사 결과 각 구조체 복사가 호출 깊이가 깊어질 때 스택 메모리를 고갈시킨다는 것이 밝혀졌습니다.
이야기
기업 서버 시스템에서 프로그래머가 지역 구조체의 포인터를 반환하여 코드에서 함수 종료 후 "포기된" 포인터에 접근했습니다. 이는 프로덕션에서 드물게 재현되는 치명적인 세그멘테이션 오류로 나타났습니다.
이야기
오픈 소스 프로젝트에서 성능이 복잡한 구조체를 값으로 반환하는 함수로 전환한 후 급격히 저하되었습니다. 프로파일러는 불필요한 구조체 복사로 인해 CPU 시간 비용이 발생하는 것을 발견했습니다.