나는 언어 자체의 기본 요소 인 비슷한 "함수"를 갖는 대신 stdlib와 같은 표준 라이브러리 (C ++, Java, Python과 같은 모든 프로그래밍 언어)가 왜 존재하는지 생각하고있었습니다.
나는 언어 자체의 기본 요소 인 비슷한 "함수"를 갖는 대신 stdlib와 같은 표준 라이브러리 (C ++, Java, Python과 같은 모든 프로그래밍 언어)가 왜 존재하는지 생각하고있었습니다.
답변:
@ Vincent 's (+1) good answer에서 다소 확장 할 수 있습니다 .
컴파일러가 단순히 함수 호출을 일련의 명령어로 변환 할 수없는 이유는 무엇입니까?
적어도 두 가지 메커니즘을 통해 가능합니다.
함수 호출 인라인 — 변환하는 동안 컴파일러는 소스 코드 호출을 함수에 대한 실제 호출 대신 직접 인라인으로 구현할 수 있습니다. 여전히 함수에는 어딘가에 정의 된 구현이 있어야하며 이는 표준 라이브러리에있을 수 있습니다.
내장 함수 — 내장 함수는 라이브러리에서 함수를 찾을 필요없이 컴파일러에 알린 함수입니다. 이들은 일반적으로 다른 방법으로는 실제로 액세스 할 수없는 하드웨어 기능을 위해 예약되어 있으므로 어셈블리 언어 라이브러리 함수 호출에 대한 오버 헤드도 높은 것으로 간주됩니다. (컴파일러는 일반적으로 자동으로 언어로 소스 코드를 인라인 할 수 있지만 내장 메커니즘이있는 어셈블리 함수는 할 수 없습니다.)
그럼에도 불구하고 가장 좋은 방법은 컴파일러가 소스 언어의 함수 호출을 기계어 코드의 함수 호출로 변환하는 것입니다. 재귀, 가상 방법 및 깎아 지른 크기는 인라인이 항상 가능한 것은 아니며 실용적이지 않은 이유입니다. 별도의 컴파일 (객체 모듈), 별도의로드 단위 (예 : DLL)와 같은 또 다른 이유는 빌드의 의도입니다.
대부분의 표준 라이브러리 함수를 intrisics로 만들면 실제로 이점이 없습니다 (실제 이점을 위해 컴파일러에 더 많은 지식을 하드 코딩 할 것입니다). 따라서 기계 코드 호출이 가장 적합합니다.
C는 표준 라이브러리 함수에 유리한 다른 명시 적 언어 설명을 생략 한 주목할만한 언어입니다. 라이브러리는 이미 존재하지만이 언어는 표준 라이브러리 함수에서 더 많은 작업을 수행하고 언어 문법의 명시 적 표현으로 줄였습니다. 예를 들어, 다른 언어로 된 IO에는 다양한 문장의 형태로 자체 구문이 자주 제공되는 반면, C 문법은 IO 문장을 정의하지 않고 단순히 표준 라이브러리를 연기하여 함수 호출을 통해 액세스 할 수있는 모든 것을 제공합니다. 컴파일러는 이미 수행 방법을 알고 있습니다.
이것은 언어 자체를 가능한 한 단순하게 유지하기위한 것입니다. 루프 유형 또는 매개 변수를 함수 등에 전달하는 방법과 같은 언어의 기능과 대부분의 응용 프로그램에 필요한 공통 기능을 구별해야합니다.
라이브러리는 많은 프로그래머에게 유용 할 수있는 함수이므로 공유 할 수있는 재사용 가능한 코드로 만들어집니다. 표준 라이브러리는 프로그래머가 일반적으로 필요로하는 매우 일반적인 기능으로 설계되었습니다. 이런 식으로 프로그래밍 언어는 더 넓은 범위의 프로그래머에게 즉시 유용합니다. 언어 자체의 핵심 기능을 변경하지 않고도 라이브러리를 업데이트하고 확장 할 수 있습니다.
PHP
예를 들어 방대한 언어 기능과 언어 자체 간에는 거의 차이가 없습니다.
include
, require
그리고 require_once
, 만약 / 대 / 동안 (구조화 프로그래밍), 예외 약한 입력 규칙 복잡 '에러 값'별도의 시스템을 복잡 연산자 우선 순위 규칙, 계속해서 . 이것을 스몰 토크, 구성표, 프롤로그, 포스 등의 단순성과 비교해보십시오.;)
다른 답변에서 이미 말한 것 외에도 표준 기능을 라이브러리에 넣는 것은 우려를 분리하는 것입니다 .
언어를 구문 분석하고 코드를 생성하는 것은 컴파일러의 일입니다. 해당 언어로 작성되어 라이브러리로 제공 될 수있는 모든 것을 포함하는 것은 컴파일러의 일이 아닙니다.
사실상 모든 프로그램에 필요한 핵심 기능 을 제공하는 것은 표준 라이브러리 (항상 암시 적으로 사용 가능한 라이브러리) 작업 입니다. 유용한 모든 기능을 포함하는 것은 표준 라이브러리의 작업이 아닙니다.
많은 프로그램이 없이도 수행 할 수있는 보조 기능을 제공하는 것은 표준 라이브러리 (선택 사항)의 역할이지만 여전히 많은 응용 프로그램에서 표준 환경으로의 배송을 보증하는 데 필수적입니다. 지금까지 작성된 모든 재사용 가능한 코드를 포함하는 것은 선택적 라이브러리의 일이 아닙니다.
유용한 재사용 가능한 함수 모음을 제공하는 것은 사용자 라이브러리의 작업입니다. 작성된 모든 코드를 포함하는 것은 사용자 라이브러리의 작업이 아닙니다.
실제로 하나의 응용 프로그램에만 관련된 나머지 코드 비트를 제공하는 것은 응용 프로그램의 소스 코드 작업입니다.
하나의 크기에 맞는 소프트웨어를 원한다면 정말 복잡한 것을 얻을 수 있습니다. 복잡성을 관리 가능한 수준으로 낮추려면 모듈화해야합니다. 그리고 부분적으로 구현할 수 있도록 모듈화해야합니다 .
스레딩 라이브러리는 단일 코어 임베디드 컨트롤러에서 가치가 없습니다. 이 임베디드 컨트롤러의 언어 구현이 pthread
라이브러리를 포함하지 않도록 허용하는 것은 올바른 일입니다.
수학 라이브러리는 FPU가없는 마이크로 컨트롤러에서도 가치가 없습니다. 다시 말하지만, sin()
마이크로 컨트롤러의 언어 구현자가 인생을 훨씬 더 쉽게 만드는 것과 같은 기능을 제공하지 않아도 됩니다.
핵심 표준 라이브러리조차도 커널을 프로그래밍 할 때 쓸모가 없습니다. write()
커널에 대한 syscall 없이는 구현할 수 없으며 , printf()
없이는 구현할 수 없습니다 write()
. 커널 프로그래머는 write()
syscall 을 제공하는 것이 당신의 임무 입니다.
표준 라이브러리에서 이러한 생략을 허용하지 않는 언어는 많은 작업에 적합하지 않습니다 . 일반적이지 않은 환경에서 언어를 유연하게 사용할 수 있으려면 표준 라이브러리가 포함 된 언어에 유연해야합니다. 언어가 표준 라이브러리에 의존할수록 실행 환경에 대해 더 많은 가정을하므로 이러한 전제 조건을 제공하는 환경으로의 사용을 제한합니다.
물론 파이썬이나 자바와 같은 고급 언어 는 환경에 대해 많은 가정을 할 수 있습니다. 그리고 그들은 표준 라이브러리에 많은 것들을 포함시키는 경향이 있습니다. C와 같은 저수준 언어는 표준 라이브러리에서 훨씬 더 적게 제공하며 핵심 표준 라이브러리를 훨씬 작게 유지합니다. 그렇기 때문에 거의 모든 아키텍처에서 작동하는 C 컴파일러를 찾을 수 있지만 파이썬 스크립트를 실행할 수 없습니다.
컴파일러와 표준 라이브러리가 분리 된 큰 이유 중 하나는 두 가지 다른 목적으로 사용되기 때문입니다 (둘 다 동일한 언어 사양으로 정의 된 경우에도 해당). 컴파일러는 더 높은 수준의 코드를 기계 명령어로 변환하고 표준 라이브러리는 사전 테스트를 제공합니다 일반적으로 필요한 기능의 구현. 컴파일러 작성자는 다른 소프트웨어 개발자와 마찬가지로 모듈성을 중요하게 생각합니다. 실제로 초기 C 컴파일러 중 일부는 컴파일러를 사전 처리, 컴파일 및 링크를 위해 별도의 프로그램으로 분할했습니다.
이 모듈성은 다음과 같은 많은 장점을 제공합니다.
역사적으로 (적어도 C의 관점에서 볼 때), 원래의 사전 표준화 버전의 언어에는 표준 라이브러리가 전혀 없었습니다. OS 공급 업체와 타사는 종종 일반적으로 사용되는 기능으로 가득 찬 라이브러리를 제공하지만 구현마다 다른 것들이 포함되어 있으며 서로 호환되지 않습니다. C가 표준화되었을 때, 그들은 이질적인 구현을 조화시키고 이식성을 향상시키기 위해 "표준 라이브러리"를 정의했습니다. C 표준 라이브러리는 Boost 라이브러리가 C ++ 용으로 개발 한 것처럼 언어와 별도로 개발되었지만 나중에 언어 사양에 통합되었습니다.
추가 코너 사례 답변 : 지적 재산권 관리
주목할만한 예는 Microsoft가 Microsoft에서 구입 한 .NET Framework에서 Math.Pow (double, double)를 구현 한 것으로 프레임 워크가 오픈 소스가 된 경우에도 공개되지 않은 상태입니다. (정확히 말하면, 위의 경우 라이브러리보다는 내부 호출이지만 아이디어는 유지됩니다.) 언어 자체와 분리 된 라이브러리 (이론적으로 표준 라이브러리의 하위 세트)는 언어 후원자에게 투명성 유지 대상과 공개되지 않은 대상 (제 3 자와의 계약 또는 기타 IP 관련 사유로 인해) 사이의 경계.
Math.Pow
에는 구매 또는 인텔에 대한 언급이 없으며 기능 구현의 소스 코드를 읽는 사람들에 대해 이야기합니다.
이것은 훌륭한 질문입니다!
예를 들어 C ++ 표준은 컴파일러 나 표준 라이브러리에서 구현해야하는 것을 지정하지 않습니다. 단지 구현을 참조합니다 . 예를 들어, 예약 된 심볼은 컴파일러 (내장형)와 표준 라이브러리에 의해 서로 바꿔서 정의됩니다.
그러나 내가 아는 모든 C ++ 구현에는 컴파일러에서 제공하는 최소한의 내장 함수와 표준 라이브러리에서 제공하는 최대한의 내장 함수가 있습니다.
따라서 기술적으로 표준 라이브러리를 컴파일러에서 고유 기능으로 정의하는 것이 가능하지만 실제로는 거의 사용되지 않는 것 같습니다.
기능의 일부를 표준 라이브러리에서 컴파일러로 옮길 생각을 생각해 보자.
장점 :
단점 :
std
실험을 위해 작은 라이브러리 (외부 ) 만 만드는 것이 더 어렵습니다 .즉, 컴파일러로 무언가를 옮기는 것은 현재와 미래에 비싸기 때문에 확실한 경우가 필요합니다. 일부 기능의 경우 필수 (일반 코드로 작성할 수 없음)가 필요하지만 컴파일러로 이동하고 표준 라이브러리에서이를 작성 하기 위해 최소한의 일반 조각을 추출 해야합니다.
언어 디자이너로서 저는 여기에 다른 답변들 중 일부를 에코하고 싶지만 언어를 구축하는 사람의 눈을 통해 제공하고 싶습니다.
가능한 모든 것을 추가하면 API가 완료되지 않습니다. API는 가능한 모든 것을 꺼내고 나면 완료됩니다.
프로그래밍 언어는 일부 언어를 사용하여 지정해야합니다. 귀하의 언어로 작성된 모든 프로그램의 의미를 전달할 수 있어야합니다. 이 언어는 매우 쓰기 하드, 심지어 더 열심히 잘 작성. 일반적으로 컴퓨터가 아니라 다른 개발자, 특히 언어에 대한 컴파일러 또는 해석기를 작성하는 개발자에게 의미를 전달하는 데 사용되는 매우 정확하고 체계적인 영어 형태 인 경향이 있습니다. 다음은 C ++ 11 사양 [intro.multithread / 14]의 예입니다.
M의 값 계산 B와 관련하여 원자 객체 M에 대한 부작용의 가시적 인 순서는 M의 수정 순서에서 부작용의 최대 연속 서브 시퀀스이며, 여기서 제 1 부작용은 B에 대하여 보인다 모든 부작용에 대해 B가 그 전에 발생하는 것은 아닙니다. 평가 B에 의해 결정된 원자 물체 M의 값은 B와 관련하여 M의 가시적 인 순서로 어떤 동작에 의해 저장된 값이어야한다. [참고 : 값의 부작용의 가시적 인 순서는 보여 질 수있다 아래의 일관성 요구 사항에 따라 계산이 고유합니다. — 끝 노트]
블렉! C ++ 11이 멀티 스레딩을 처리하는 방법을 이해하는 데 뛰어 들었던 사람은 왜 문구가 너무 불투명 해야하는지 이해할 수 있지만 그 사실이 ... 음 ... 너무 불투명하다는 사실을 용서하지는 않습니다!
std::shared_ptr<T>::reset
표준의 라이브러리 섹션에서 의 정의와 대조 하십시오.
template <class Y> void reset(Y* p);
효과 : 동등
shared_ptr(p).swap(*this)
차이점은 무엇입니까? 언어 정의 부분에서, 작가는 독자가 언어 프리미티브를 이해한다고 가정 할 수 없습니다. 모든 것은 영어 산문으로 신중하게 지정해야합니다. 라이브러리 정의 부분에 도달하면 언어를 사용하여 동작을 지정할 수 있습니다. 이것은 종종 훨씬 쉽다!
원칙적으로, "언어 프리미티브 (language primitives)"와 "표준 라이브러리"기능. 실제로이 줄은 표현하기 위해 설계된 언어를 사용하여 언어의 가장 복잡한 부분 (예 : 알고리즘을 구현해야하는 부분)을 작성할 수 있기 때문에 그리는 데 매우 유용합니다.
그리고 실제로 흐릿한 선이 보입니다.
java.lang.ref.Reference<T>
수 만 표준 라이브러리 클래스에 의해 서브 클래스 java.lang.ref.WeakReference<T>
java.lang.ref.SoftReference<T>
및 java.lang.ref.PhantomReference<T>
때문에의 행동에 Reference
너무 깊이가 "표준 라이브러리"클래스로 구현하는 과정의 부분에 일부 제한을 넣을 필요가 있다고 Java 언어 사양과 짝을 이루고있다.이는 기존 답변에 대한 추가로 의미가 있습니다 (댓글이 너무 깁니다).
표준 라이브러리에는 다른 두 가지 이유가 있습니다.
특정 언어 기능이 라이브러리 함수에 있고 어떻게 작동하는지 알고 싶다면 해당 함수의 소스를 읽을 수 있습니다. 버그 보고서 / 패치 / 풀 요청을 제출하려면 일반적으로 수정 및 테스트 사례를 코딩하는 것이 어렵지 않습니다. 컴파일러에 있다면 내부를 파헤칠 수 있어야합니다. 동일한 언어로되어 있더라도 (자체 존중 컴파일러는 자체 호스팅되어야 함) 컴파일러 코드는 응용 프로그램 코드와 다릅니다. 올바른 파일을 찾는 데에도 시간이 오래 걸릴 수 있습니다.
당신이 그 길을 가면 많은 잠재적 인 기여자들로부터 자신을 차단하고 있습니다.
많은 언어에서이 기능을 어느 정도 제공하지만 핫 리로드를 수행하는 코드를 핫 리로드하는 것은 매우 복잡합니다. SL이 런타임과 분리 된 경우 다시로드 할 수 있습니다.
이것은 흥미로운 질문이지만 이미 많은 좋은 답변이 있으므로 완전한 답변을 시도하지는 않습니다.
그러나 내가 생각하지 않는 두 가지 사항은 충분히주의를 기울였습니다.
첫 번째는 모든 것이 매우 명확하지 않다는 것입니다. 다르게 행동해야 할 이유가 있기 때문에 약간의 스펙트럼입니다. 예를 들어, 컴파일러는 종종 표준 라이브러리 및 해당 기능에 대해 알고 있습니다. 예제의 예 : C의 "Hello World"함수 인 printf는 내가 생각할 수있는 가장 좋은 것입니다. 그것은 라이브러리 함수이며, 플랫폼에 따라 다르기 때문에 정렬되어야합니다. 그러나 잘못된 호출에 대해 프로그래머에게 경고하려면 컴파일러에서 동작 (구현 정의)을 알아야합니다. 이것은 특히 깔끔하지는 않지만 좋은 타협으로 보였습니다. 덧붙여서, 이것은 대부분의 "이 디자인이 왜 필요한지"질문에 대한 진정한 해답입니다. 항상 "이것이 분명한 방법이었다"또는 "
둘째는 표준 라이브러리가 모든 표준이 될 수 없다는 것입니다. 언어가 바람직한 상황은 많지만 일반적으로 언어와 함께 제공되는 표준 라이브러리는 실용적이지 않고 바람직하지 않습니다. 비표준 플랫폼에서 C와 같은 시스템 프로그래밍 언어의 경우가 가장 일반적입니다. 예를 들어, OS 또는 스케줄러가없는 시스템이있는 경우 스레딩이 없습니다.
표준 라이브러리 모델 (및 스레딩이 지원됨)을 사용하면이를 깨끗하게 처리 할 수 있습니다. 컴파일러는 거의 동일하며 적용되는 라이브러리의 비트를 제거하고 제거 할 수없는 것은 재사용 할 수 있습니다. 이것이 컴파일러에 구워지면 문제가 발생하기 시작합니다.
예를 들면 다음과 같습니다.
호환되는 컴파일러는 될 수 없습니다.
표준과의 편차를 어떻게 표시 하시겠습니까? 일반적으로 파이썬 가져 오기 또는 표준 라이브러리 모델에 누락 된 항목이 있으면 쉽게 문제를 가리키는 C 포함 포함 형식의 가져 오기 / 포함 구문이 있습니다.
'라이브러리'기능을 조정하거나 확장하려는 경우에도 비슷한 문제가 발생합니다. 생각보다 훨씬 일반적입니다. 스레딩을 고수하기 위해 : Windows, Linux 및 일부 이국적인 네트워크 처리 장치는 모두 다르게 스레딩을 수행합니다. 리눅스 / 윈도우 비트는 상당히 정적이고 동일한 API를 사용할 수 있지만 NPU는 요일에 따라 바뀌고 API도 함께 변경됩니다. 이런 종류의 일을 분리 할 방법이 없다면 사람들은 어떤 비트를 지원 / 수행 할 필요가 없는지 신속하게 결정할 수있다.