이 답변 에서 제안했듯이 하드웨어 디자인의 문제이지만 언어 디자인의 전통도 중요한 역할을합니다.
함수가 반환하면 특정 레지스터의 반환 객체에 대한 포인터를 남깁니다.
Fortran, Lisp 및 COBOL의 세 가지 첫 번째 언어 중 첫 번째 언어는 수학을 모델로 한 단일 반환 값을 사용했습니다. 두 번째는 목록과 같은 방식으로 임의의 수의 매개 변수를 반환했습니다 (목록의 주소 인 단일 매개 변수 만 전달하고 반환한다고 주장 할 수도 있음). 세 번째는 0 또는 하나의 값을 반환합니다.
이 첫 번째 언어는 그 이후의 언어 디자인에 많은 영향을 미쳤지 만, 여러 값을 반환 한 유일한 언어 인 Lisp는 큰 인기를 얻지 못했습니다.
C가 그 언어에 영향을 받았을 때 C는 하드웨어 리소스의 효율적인 사용에 중점을 두어 C 언어와 C 언어를 구현 한 기계 코드 사이의 밀접한 관계를 유지했습니다. "auto"대 "register"변수와 같은 가장 오래된 기능 중 일부는 디자인 철학의 결과입니다.
또한 어셈블리 언어는 주류 개발 단계에서 단계적으로 폐지되기 시작한 80 년대까지 널리 사용되었다는 점도 지적해야합니다. 컴파일러를 작성하고 언어를 만든 사람들은 어셈블리 에 대해 잘 알고 있었고 대부분 가장 잘 작동하는 것을 유지했습니다.
이 표준에서 벗어난 대부분의 언어는 큰 인기를 얻지 못했기 때문에 언어 디자이너의 결정에 영향을 미치는 강력한 역할을 수행하지 않았습니다.
어셈블리 언어에 대해 알아 보겠습니다. 먼저 Apple II 및 VIC-20 마이크로 컴퓨터에서 널리 사용되는 1975 년 마이크로 프로세서 인 6502를 살펴 보겠습니다 . 프로그래밍 언어가 시작될 때 30 년 전의 20 대 컴퓨터에 비해 강력하지만 당시의 메인 프레임과 미니 컴퓨터에 사용 된 것에 비해 매우 약했습니다.
기술적 인 설명을 보면 5 개의 레지스터와 몇 개의 1 비트 플래그가 있습니다. 유일한 "전체"레지스터는 프로그램 카운터 (PC)였습니다.이 레지스터는 다음에 실행될 명령을 가리 킵니다. 다른 하나는 누산기 (A), 두 개의 "인덱스"레지스터 (X 및 Y) 및 스택 포인터 (SP)를 등록합니다.
서브 루틴을 호출하면 SP가 가리키는 메모리에 PC가 배치되고 SP가 감소합니다. 서브 루틴에서 복귀하면 반대로 작동합니다. 스택에서 다른 값을 밀고 당길 수는 있지만 SP와 관련된 메모리를 참조하기는 어렵 기 때문에 재진입 서브 루틴을 작성하는 것이 어려웠습니다. 우리가 느낀 것처럼 언제든지 서브 루틴을 호출하는 것은 당연한 것으로 여겨졌지만이 아키텍처에서는 그리 일반적이지 않았습니다. 종종, 매개 변수와 서브 루틴 리턴 주소가 별도로 유지되도록 별도의 "스택"이 작성됩니다.
6502, 6800 에서 영감을 얻은 프로세서를 살펴보면 SP만큼 넓은 추가 레지스터 인 인덱스 레지스터 (IX)가 있으며 SP에서 값을받을 수 있습니다.
머신에서 재진입 서브 루틴 호출은 스택의 매개 변수 푸시, PC 푸시, PC를 새 주소로 변경 한 다음 서브 루틴이 로컬 변수를 스택으로 푸시하는 것으로 구성 됩니다. 로컬 변수 및 매개 변수의 수는 알려져 있으므로 스택을 기준으로 주소 지정을 수행 할 수 있습니다. 예를 들어, 두 개의 매개 변수를 수신하고 두 개의 로컬 변수를 갖는 함수는 다음과 같습니다.
SP + 8: param 2
SP + 6: param 1
SP + 4: return address
SP + 2: local 2
SP + 0: local 1
모든 임시 공간이 스택에 있기 때문에 여러 번 호출 할 수 있습니다.
8080 의 간접 레지스터, HL에 터지는 후 스택에 SP를 밀고에 의해, 6800과 비슷한 뭔가를 할 수 TRS-80과 CP / M 기반 마이크로 컴퓨터의 호스트에 사용.
이것은 구현하는 매우 일반적인 방법이며 더 현대적인 프로세서에서 더 많은 지원을 얻었습니다.베이스 포인터를 사용하면 모든 로컬 변수를 쉽게 반환하기 전에 덤프 할 수 있습니다.
문제는 어떻게 당신이 무엇을 반환 합니까? 프로세서 레지스터는 초기에는 그리 많지 않았으며, 어떤 레지스터를 처리 할 메모리를 찾기 위해 일부를 사용해야하는 경우가 종종있었습니다. 스택에 물건을 반환하는 것은 복잡합니다. 모든 것을 팝하고 PC를 저장하고 반환 매개 변수 (그 동안 저장되어 있습니까?)를 누른 다음 PC를 다시 밀고 돌아와야합니다.
따라서 일반적으로 수행 된 작업은 하나의 레지스터 를 반환 값 으로 예약 하는 것이 었습니다 . 호출 코드는 반환 값이 특정 레지스터에있을 것임을 알았습니다.이 값은 저장되거나 사용될 때까지 보존되어야합니다.
여러 반환 값을 허용하는 언어를 살펴 보겠습니다. Forth. Forth가하는 일은 별도의 리턴 스택 (RP)과 데이터 스택 (SP)을 유지하는 것이므로 모든 기능은 모든 매개 변수를 팝하고 리턴 값을 스택에 남겨 두어야합니다. 반환 스택은 분리되어 있었기 때문에 방해가되지 않았습니다.
컴퓨터를 사용한 첫 6 개월 동안 어셈블리 언어와 Forth를 배운 사람이라면 여러 반환 값이 전적으로 정상적인 것처럼 보입니다. /mod
정수 나누기 와 나머지 를 반환하는 Forth와 같은 연산자 는 분명해 보입니다. 반면에, 초기 경험이 C 인 사람이 그 개념이 이상하다는 것을 쉽게 알 수 있습니다. 그것은 "기능"이 무엇인지에 대한 그들의 뿌리 깊은 기대에 어긋납니다.
수학은 ... 수학 수업에서 기능을하기 전에 컴퓨터를 프로그래밍하고있었습니다. 이 인 이 아닌 전체 부분이있다, 다시, CS 및 수학에 의해 영향을 받는다 프로그래밍 언어의 전체 부분은 있지만.
따라서 수학이 초기 언어 설계에 영향을 미치는 요인, 하드웨어 제약으로 인해 쉽게 구현되는 내용 및 인기있는 언어가 하드웨어의 진화 방식에 영향을 미치는 요인이 합류했습니다 (Lisp 기계 및 Forth 기계 프로세서는이 프로세스에서로드 킬이었습니다).