문서의 각 단락이 어느 리비전에서 마지막으로 수정되었는지 확인할 수 있습니다. 왼쪽의 정보 칩을 통해 작성자와 수정 시점을 파악하세요.

참조에 의한 호출 | |
정의 | 프로그래밍 언어에서 함수나 서브루틴에 인수를 전달하는 방식 중 하나로, 호출되는 함수가 호출자의 인수에 대한 참조(주소)를 받아, 함수 내부에서 해당 인수의 값을 직접 변경할 수 있도록 하는 방식. |
유형 | 인수 전달 방식 |
주요 용도 | 함수 내부에서 호출자의 변수 값을 수정해야 할 때 메모리 주소를 전달하여 대용량 데이터 구조를 효율적으로 처리할 때 |
관련 분야 | 프로그래밍 언어 컴파일러 설계 메모리 관리 |
대표 언어 | C++ (참조자 &) C# (ref, out 키워드) Visual Basic .NET (ByRef) FORTRAN |
상세 정보 | |
동작 방식 | 호출하는 측(caller)의 변수 메모리 주소가 함수에 전달됨. 함수는 전달받은 주소를 통해 원본 변수에 직접 접근하여 읽기/쓰기 수행. |
장점 | 함수 내에서 원본 데이터를 직접 수정할 수 있어 부작용(side effect)을 명시적으로 활용 가능. 값에 의한 호출(Call by value)과 달리 데이터 복사가 발생하지 않아, 큰 구조체나 객체를 전달할 때 성능상 유리. |
단점 | 의도하지 않게 호출자의 변수 값이 변경될 수 있어 프로그램의 예측 가능성이 낮아질 수 있음. 참조 대상 변수의 수명을 관리해야 하는 복잡성이 추가될 수 있음. |
반대 개념 | 값에 의한 호출(Call by value) |
참고 개념 | 공유에 의한 호출(Call by sharing) 포인터 |

참조에 의한 호출은 함수나 메서드에 인수를 전달하는 주요 방식 중 하나이다. 이 방식은 호출하는 측의 실제 변수에 대한 참조, 즉 메모리 주소를 함수에 전달한다. 따라서 함수 내부에서는 이 참조를 통해 원본 변수의 저장 공간에 직접 접근하여 값을 읽거나 수정할 수 있다. 이는 호출된 함수의 조작이 호출자의 변수에 직접적인 영향을 미칠 수 있음을 의미한다.
이 방식은 함수 내부에서 호출자의 변수 값을 수정해야 하는 경우나, 대용량의 데이터 구조를 복사 없이 효율적으로 처리할 때 주로 사용된다. C++에서는 참조자(&)를, C#에서는 ref나 out 키워드를 사용하여 명시적으로 참조에 의한 호출을 구현한다. FORTRAN과 같은 초기 언어에서도 기본적인 인수 전달 방식으로 채택되었다.
참조에 의한 호출은 값에 의한 호출과 대비되는 개념이다. 값에 의한 호출은 인수의 값만을 복사하여 전달하므로, 함수 내부에서 매개변수를 변경해도 원본 변수는 영향을 받지 않는다. 반면 참조에 의한 호출은 원본 데이터에 대한 작업을 가능하게 하여 메모리 효율성을 높일 수 있지만, 의도치 않게 원본 데이터를 변경하는 부작용을 초래할 위험이 따른다.
이 인수 전달 방식은 프로그래밍 언어의 설계와 컴파일러의 동작 방식, 그리고 메모리 관리와 깊은 연관이 있다. 다양한 언어들이 각자의 철학에 따라 이 방식을 지원하거나, 자바의 객체 참조 전달과 같은 변형된 형태로 구현하기도 한다.

참조에 의한 호출은 함수에 인수를 전달하는 두 가지 주요 방식 중 하나로, 값에 의한 호출과 대비된다. 값에 의한 호출에서는 호출하는 쪽의 인수 값이 복사되어 함수의 매개변수로 전달된다. 이 경우 함수 내부에서 매개변수의 값을 변경해도, 원본 인수 변수의 값에는 아무런 영향을 미치지 않는다. 반면 참조에 의한 호출에서는 인수 변수의 메모리 주소, 즉 참조가 전달된다. 함수는 이 주소를 통해 원본 데이터에 직접 접근하여 작업을 수행하므로, 함수 내부에서의 변경 사항이 호출자의 원본 변수에 그대로 반영된다.
이러한 차이는 메모리 사용과 동작 방식에서 명확히 드러난다. 값에 의한 호출은 데이터의 복사본을 만들기 때문에, 특히 구조체나 큰 배열과 같은 대용량 데이터를 전달할 때 메모리와 성능에 부담이 될 수 있다. 하지만 원본 데이터가 훼손될 위험이 없어 안전성이 높다. 참조에 의한 호출은 메모리 주소만 전달하므로 대용량 데이터를 효율적으로 처리할 수 있지만, 함수의 부작용으로 인해 원본 데이터가 의도치 않게 변경될 수 있는 위험이 따른다.
많은 현대 프로그래밍 언어들은 명시적인 참조 전달 방식을 지원한다. 예를 들어, C++에서는 매개변수 타입에 앰퍼샌드(&)를 붙여 참조자를 선언하며, C#에서는 ref나 out 키워드를 사용한다. 한편 자바와 파이썬과 같은 언어는 공식적으로는 값에 의한 호출만을 지원한다고 설명되지만, 객체에 대한 참조 값이 복사되어 전달되기 때문에 객체의 내부 상태를 함수에서 변경할 수 있다. 이는 흔히 "객체 참조의 값에 의한 전달"로 설명되며, 순수한 참조에 의한 호출과는 개념상 미묘한 차이가 있다.

참조에 의한 호출의 핵심 동작 원리는 메모리 주소를 전달하는 것이다. 함수가 호출될 때, 호출자는 인자로 사용한 변수의 실제 메모리 주소(또는 참조)를 함수에 넘겨준다. 이는 변수 자체의 복사본을 생성하는 값에 의한 호출과 근본적으로 다르다. 함수는 전달받은 주소를 통해 원본 변수가 위치한 메모리 공간에 직접 접근할 수 있게 된다.
이 방식은 특히 C++와 같은 언어에서 명시적으로 구현된다. C++에서는 매개변수 타입 뒤에 앰퍼샌드(&) 기호를 붙여 참조자를 선언하며, 이 매개변수는 호출 시 전달된 원본 변수의 별칭(alias)이 된다. 함수 내부에서 이 참조자에 가하는 모든 조작은 원본 변수에 그대로 반영된다. 마찬가지로 C# 언어에서는 ref 또는 out 키워드를 사용하여 메모리 주소에 의한 전달을 명시한다.
메모리 주소를 직접 전달하는 이 방식의 가장 큰 장점은 효율성이다. 크기가 큰 구조체나 객체를 함수의 인자로 넘겨야 할 때, 값을 복사하는 대신 주소만 전달하면 메모리 사용과 복사에 드는 시간을 크게 절약할 수 있다. 또한, 함수는 하나의 반환값만을 돌려줄 수 있는 제약이 있는데, 참조로 전달된 여러 매개변수를 수정함으로써 효과적으로 여러 결과값을 반환하는 것과 같은 효과를 낼 수 있다.
그러나 이는 동시에 주요한 주의사항이 된다. 함수 내부에서 원본 데이터를 의도치 않게 변경하는 부작용이 발생하기 쉽기 때문이다. 이로 인해 프로그램의 흐름을 추적하고 디버깅하기가 어려워질 수 있다. 따라서 참조에 의한 호출은 성능 향상이 필요하거나 함수 외부의 변수 상태를 명시적으로 변경해야 하는 경우에 한정하여 신중하게 사용해야 한다.
참조에 의한 호출 방식으로 함수가 호출되면, 함수는 전달받은 메모리 주소를 통해 호출자의 원본 변수에 직접 접근한다. 이는 함수 내부에서 매개변수에 가하는 모든 조작이 호출자의 실제 데이터에 즉시 반영됨을 의미한다. 예를 들어, 함수 내에서 매개변수의 값을 증가시키거나, 배열의 특정 요소를 수정하거나, 객체의 속성을 변경하는 작업은 모두 원본 변수를 직접 변경하는 부작용을 발생시킨다.
이러한 직접적인 조작은 함수의 스코프를 넘어서는 영향을 미치기 때문에, 의도적으로 호출자의 데이터를 수정하려는 경우에는 유용하지만, 실수로 원치 않는 변경을 초래할 위험도 동시에 내포한다. 특히 대규모 소프트웨어 시스템에서 여러 함수가 동일한 데이터를 참조로 공유하고 조작할 경우, 프로그램의 상태를 예측하기 어렵게 만들고 디버깅을 복잡하게 할 수 있다.
참조에 의한 호출을 지원하는 언어들은 대체로 이 방식의 사용을 명시적으로 표시하도록 요구하여, 프로그래머가 의도를 인지하고 사용하도록 유도한다. 예를 들어, C++에서는 매개변수 타입에 참조자(&)를 붙여 선언하며, C#에서는 함수 호출 시 ref나 out 키워드를 인수 앞에 반드시 명시해야 한다. 이는 값에 의한 호출과의 동작 차이를 코드 상에서 명확히 구분하는 역할을 한다.
따라서 함수 내부에서의 조작은 원본 데이터에 대한 직접적이고 영구적인 변경을 가능하게 하는 강력한 도구이지만, 그만큼 신중한 설계와 사용이 요구된다. 이 방식은 대용량 구조체나 객체를 효율적으로 전달하거나, 하나의 함수 호출로 여러 개의 결과 값을 반환해야 하는 상황 등에서 주로 활용된다.

C#에서는 참조에 의한 호출을 명시적으로 구현하기 위해 ref와 out 키워드를 제공한다. 이 키워드들은 메서드의 매개변수와 인수 앞에 사용되며, 메서드에 변수의 참조, 즉 메모리 주소를 전달한다는 것을 나타낸다. 이를 통해 메서드 내부에서 전달된 원본 변수의 값을 직접 읽고 수정할 수 있게 된다.
ref 키워드는 참조로 전달되는 인수가 메서드 호출 전에 명시적으로 초기화되어야 함을 의미한다. 메서드는 이 인수의 값을 읽을 수도 있고 변경할 수도 있다. 반면 out 키워드는 메서드가 해당 매개변수에 반드시 값을 할당하여 호출자에게 '출력'하도록 강제한다는 점이 다르다. 따라서 out 매개변수로 전달되는 인수는 메서드 호출 전에 초기화할 필요가 없지만, 메서드는 반드시 그 값을 할당해야 한다.
이 두 키워드는 값에 의한 호출이 기본인 C#에서 메서드가 하나 이상의 결과를 반환해야 하거나, 대용량 구조체를 효율적으로 전달해야 할 때 유용하게 사용된다. ref와 out을 사용하는 메서드를 호출할 때는 인수 앞에도 동일한 키워드를 붙여야 하며, 이는 의도를 명확히 하고 실수를 방지하는 역할을 한다.
C# 7.0부터는 in 키워드가 추가되어 참조에 의한 전달을 허용하지만 메서드 내에서 수정은 불가능한 읽기 전용 참조를 정의할 수 있게 되었다. 이는 성능 최적화를 위해 큰 구조체를 전달할 때 유용하며, C++의 const&와 유사한 개념이다.

참조에 의한 호출 방식은 메모리 사용 측면에서 뚜렷한 효율성을 가진다. 이 방식은 함수에 인자를 전달할 때 실제 데이터의 복사본을 새로 생성하는 대신, 원본 데이터가 위치한 메모리 주소만을 전달한다. 따라서 값에 의한 호출 방식과 달리, 전달되는 데이터의 크기와 상관없이 항상 고정된 크기의 주소값만이 복사되므로 함수 호출 오버헤드가 매우 작다. 이는 특히 배열, 구조체, 객체와 같이 크기가 큰 데이터 구조를 함수의 매개변수로 다룰 때 큰 장점으로 작용한다.
이러한 메모리 효율성은 시스템의 전체적인 성능 향상으로 이어진다. 대용량 데이터를 처리하는 함수를 빈번히 호출해야 하는 상황에서, 매번 데이터 전체를 복사하는 것은 시간과 메모리 공간을 낭비한다. 참조에 의한 호출을 사용하면 복사 작업이 필요 없어 실행 속도가 빨라지고, 불필요한 메모리 할당과 해제가 줄어들어 가비지 컬렉션의 부담을 낮출 수 있다. 이는 실시간 시스템이나 제한된 하드웨어 자원을 가진 임베디드 시스템 프로그래밍에서 중요한 고려 사항이 된다.
그러나 이 효율성은 원본 데이터에 대한 직접적인 접근 권한을 부여하는 대가로 얻어진다. 함수 내부에서 참조를 통해 전달된 인자의 값을 변경하면, 호출자의 원본 변수 값도 함께 변경되는 부작용이 발생한다. 이는 의도적인 경우에는 유용하지만, 실수로 인한 예기치 않은 데이터 변경은 프로그램의 논리적 오류를 유발할 수 있다. 따라서 참조에 의한 호출을 사용할 때는 함수의 계약을 명확히 문서화하고, 변경 가능성이 없는 데이터에는 상수 참조를 사용하는 등 주의가 필요하다.
참조에 의한 호출의 가장 큰 단점은 의도하지 않은 부작용이 발생할 수 있다는 점이다. 함수가 호출자의 원본 변수를 직접 조작할 수 있기 때문에, 함수 내부에서 인수의 값을 변경하면 그 영향이 함수 외부로 즉시 전파된다. 이는 함수의 동작을 예측하기 어렵게 만들고, 프로그램의 상태를 추적하는 데 복잡성을 더한다. 특히 대규모 소프트웨어 프로젝트에서 여러 함수가 동일한 변수를 참조로 받아 조작할 경우, 디버깅이 매우 어려워질 수 있다.
이러한 부작용은 프로그램의 가독성과 유지보수성을 저하시킨다. 함수가 명시적으로 값을 반환하는 대신 참조 매개변수를 통해 상태를 변경하면, 코드를 읽는 사람은 함수의 시그니처만으로는 그 함수가 외부 상태에 어떤 영향을 미치는지 알기 어렵다. 이는 순수 함수의 개념과 대비되며, 함수형 프로그래밍 패러다임에서는 일반적으로 참조에 의한 호출을 지양하는 이유이기도 하다.
또한, 참조로 전달된 변수에 대한 접근을 잘못 관리하면 데이터 무결성이 훼손될 위험이 있다. 예를 들어, 함수가 널 포인터나 유효하지 않은 메모리 주소를 참조로 받았을 때, 이를 검사하지 않고 접근하면 프로그램이 비정상 종료될 수 있다. C++의 참조자는 초기화 시 반드시 유효한 객체를 가리켜야 하므로 이런 위험에서 상대적으로 자유롭지만, 포인터를 사용해 참조 전달을 구현하는 경우에는 이러한 위험이 항상 존재한다.
따라서 참조에 의한 호출을 사용할 때는 그 필요성을 신중히 고려해야 한다. 함수의 목적이 명확히 호출자의 변수 값을 수정하는 것일 때, 그리고 그 변경 사항이 함수 이름이나 문서에 명시적으로 드러날 때 사용하는 것이 바람직하다. 그렇지 않으면, 값에 의한 호출을 사용하거나 변경된 값을 반환값으로 돌려주는 방식이 더 안전하고 이해하기 쉬운 코드를 만드는 데 도움이 된다.

참조에 의한 호출은 함수 내부에서 호출자의 원본 변수 값을 수정해야 하는 상황에서 자주 사용된다. 대표적인 예로 두 변수의 값을 서로 교환하는 swap 함수를 들 수 있다. 값에 의한 호출을 사용하면 복사본만 교환되어 원본은 변하지 않지만, 참조에 의한 호출을 사용하면 메모리 주소를 통해 원본 변수에 직접 접근하여 값을 성공적으로 바꿀 수 있다. 이는 알고리즘 구현이나 자료 구조 조작 시 기본적인 도구로 활용된다.
또 다른 주요 사용 예는 대용량 데이터를 효율적으로 처리하는 경우다. 예를 들어, 매우 큰 배열이나 복잡한 객체를 함수의 매개변수로 전달할 때, 값에 의한 호출은 전체 데이터를 복사하는 오버헤드를 발생시킨다. 반면 참조에 의한 호출은 데이터의 주소만 전달하므로 메모리 사용과 실행 속도 측면에서 훨씬 효율적이다. 이는 GPU 프로그래밍이나 대규모 과학 계산 시뮬레이션에서 성능에 결정적 영향을 미칠 수 있다.
C++에서는 참조자(&)를, C#에서는 ref 또는 out 키워드를 사용하여 이 방식을 명시적으로 구현한다. 예를 들어, 사용자 입력을 검증하고 결과를 여러 개의 변수에 반환해야 하는 메서드를 작성할 때, out 매개변수를 사용하면 반환값 하나로는 부족한 정보를 효율적으로 전달할 수 있다. 한편, 자바와 파이썬과 같은 언어는 공식적으로는 값에 의한 호출만을 지원하지만, 객체에 대한 참조가 전달되는 방식으로 동작하기 때문에, 메서드 내에서 전달된 객체의 상태를 변경하는 것이 가능하다.
