2009-08-21 11 views
6

분명히 (최소한 gcc -std=c99에 따르면) C99는 함수 오버로드를 지원하지 않습니다. C에서 새로운 기능을 지원하지 않는 이유는 일반적으로 이전 버전과의 호환성이지만,이 경우 함수 오버로딩이 이전 버전과의 호환성을 깰 수있는 단일 사례는 생각할 수 없습니다. 이 기본 기능을 포함하지 않는 이유는 무엇입니까?C99에서 함수 오버로드를 지원하지 않는 이유가 있습니까?

+2

함수 오버로딩에서 C를 원한다면 C++을 살펴 보는 것이 좋습니다. – SingleNegationElimination

+0

@ 윌리암, 여기에 C 이론적 인 문서에서 찾은 내용이 있습니다. "매개 변수가 사용되지 않는다는 것이 알려지면 호출에서 후미 매개 변수를 생략하는 기존 방법은 일관되게 권장되지 않습니다. 이러한 매개 변수를 생략하면 동등하지 않습니다 호출과 선언 사이의 동작은 정의되어 있지 않으며 최대로 이식 가능한 프로그램은이 사용을 피할 것입니다. 따라서 구현은 고정 인수 목록에 대한 함수 호출 메커니즘을 구현하는 데 자유 롭습니다. 번호 또는 인수 유형이 제공되어야한다 "고 말했다. –

+0

(http://www.lysator.liu.se/c/rat/c3.html#3-3-2-2) –

답변

27

C에서 오버로드가 발생하지 않는 이유를 이해하려면 C++에서 오버로드를 처리하는 방법을 더 잘 이해하는 것이 도움이 될 수 있습니다.

코드를 컴파일했지만 실행 준비가되기 전에 중간 코드는이어야합니다. 이것은 컴파일 된 함수 및 다른 객체의 거친 데이터베이스를로드/실행 바이너리 파일로 변환합니다. 이 추가 단계는 컴파일 된 프로그램에서 사용할 수있는 모듈 방식의 기본 메커니즘이기 때문에 중요합니다. 이 단계에서는 기존 라이브러리에서 코드를 가져 와서 자신의 응용 프로그램 논리와 혼합 할 수 있습니다.

이 단계에서 개체 코드는 기능의 조합과 함께 모든 언어로 작성되었을 수 있습니다. 이를 가능하게하려면 링커가 다른 객체가 참조 할 때 올바른 객체를 선택할 수 있도록 일종의 관례가 있어야합니다. 어셈블리 언어로 코딩하는 경우 레이블을 정의 할 때 사용자가 수행하는 작업을 알고 있다고 가정하기 때문에 해당 레이블이 정확하게 사용됩니다. C에서

이 기능은 링커에 대한 기호의 이름이됩니다, 그래서 당신은

int main(int argc, char **argv) { return 1; } 

을 쓸 때 컴파일러는 main라는 개체를 포함하는 오브젝트 코드의 아카이브를 제공합니다.

이것은 잘 작동하지만 링커가 사용할 이름을 결정할 수 없으므로 동일한 이름을 가진 두 개의 객체를 가질 수 없습니다. 링커는 인수 유형에 대해서는 알지 못하며 일반적으로 코드에 대해서는 거의 알지 못합니다.

C++은 추가 정보를 기호 이름에 직접 인코딩하여이를 해결합니다. 반환 형식과 인수의 수 및 유형이 심볼 이름에 추가되며 함수 호출 시점에서 이러한 방식으로 참조됩니다. 링커는 알 수 있듯이 함수 호출이 모호하지 않기 때문에 이것이 발생하고 있다는 것을 알 필요가 없습니다.

이 단점은 기호 이름이 원래 함수 이름처럼 보이지 않는다는 것입니다. 특히 오버로드 된 함수의 이름이 무엇인지 예측하여 해당 함수에 연결할 수있는 것은 거의 불가능합니다. foriegn 코드로 링크하려면 extern "C"을 사용하면 해당 함수가 C 스타일의 심볼 이름을 따르게되지만 물론 이러한 함수에 과부하를 걸 수는 없습니다.

이러한 차이점은 각 언어의 디자인 목표와 관련이 있습니다. C는 이식성과 상호 운용성을 지향합니다. C는 예측 가능하고 호환 가능한 작업을 수행하지 않습니다. C++은 풍부하고 강력한 시스템을 구축하기 위해 더욱 강하게 지향되며 다른 언어와의 상호 작용에 중점을 두지 않습니다.

C가 C++와 상호 작용하기 어려운 코드를 생성하는 기능을 추구하는 것은 거의 불가능하다고 생각합니다.

편집 : Imagist 묻습니다 : 당신이 주요 INT 해결하는 경우

가 정말 기능과 상호 작용하기가 더 어렵 적은 휴대용 또는 수 있을까요 ( 는 argc, 문자를 int로 ** argv를) main-int-int-char **와 같이 주 대신에 (이것은 표준의 일부였습니다)? 여기에 문제가 표시되지 않습니다. 사실, 당신에게 이상 (최적화를 위해 사용될 수 등) 정보

이 대답하기 위해, 나는 C 다시 켜집니다 ++하고 오버로드를 처리하는 방법을 제공 나에게 보인다 . C++은이 메커니즘을 거의 똑같이 사용하지만 한가지주의해야합니다. C++은 자체의 특정 부분을 구현하는 방법을 표준화하지 않은 다음 그 누락의 결과 중 일부가 어떻게 나오는지 제안합니다. 특히 C++에는 가상 클래스 멤버가 포함 된 리치 유형 시스템이 있습니다. 이 기능을 구현하는 방법은 컴파일러 작성자에게 맡기고 vtable 해상도의 세부 사항은 함수 시그니처에 큰 영향을 미칩니다. 이러한 이유 때문에 C++은 컴파일러 작성자가 이러한 주요 기능의 구현이 다른 컴파일러 또는 동일한 컴파일러에서 이름 맹 글링을 서로 호환 할 수 없게 만들 것을 제안합니다.

이것은 C++ 및 C와 같은 고급 언어에서 자세한 유형 시스템이 있지만 더 낮은 레벨의 기계 코드는 완전히 유형이 없다는 더 심각한 문제의 증상 일뿐입니다. 임의로 리치 타입 시스템은 머신 레벨에서 제공되는 타입이 지정되지 않은 바이너리 위에 구축됩니다. 링커는 상위 수준 언어에서 사용할 수있는 다양한 형식의 정보에 액세스 할 수 없습니다. 링커는 모든 유형 추상화를 처리하고 적절하게 유형이없는 객체 코드를 생성하기 위해 컴파일러에 완전히 의존합니다.

C++은 변환 된 개체 이름에 필요한 모든 형식 정보를 인코딩하여이 작업을 수행합니다. 그러나 C는 일종의 휴대용 어셈블리 언어를 목표로 상당히 다른 초점을두고 있습니다. C는 선언 된 이름과 결과 객체의 기호 이름 사이에 엄격한 일대일 대응을 선호합니다. C가 표준화되고 예측 가능한 방식으로 이름을 섞어 놓은 경우 변경된 이름을 원하는 기호 이름과 일치 시키려면 많은 노력을 기울여야합니다. 그렇지 않으면 C++에서와 같이 해제해야합니다. 이 추가 노력은 C++과 달리 C의 유형 시스템이 상당히 작고 간단하기 때문에 거의 이점이 없습니다.

동시에, 인자로 취하는 타입에 의해서만 변화하는 유사하게 명명 된 C 함수 몇 개를 정의하는 것은 실제적인 표준 연습입니다. OpenGL namespace.

+1

만약'int main (int argc, char ** argv)'를'main-int-int-char **'와 같은 것으로 해석했다면 함수와 상호 작용하기가 어렵거나 어렵다. '(그리고 이것은 표준의 일부였습니다)? 여기에 문제가 보이지 않습니다. 사실, 이것은 당신에게 * 더 많은 정보를 줄 것입니다. (최적화 등을 위해 사용될 수 있습니다). – Imagist

+0

@Imagist - 언어에 유용합니다. 또한 새로운 C 코드로 모든 오래된 C 라이브러리를 즉시 사용할 수 없도록 만들고, 모든 최신 C 라이브러리는 오래된 C 코드로 사용할 수 없게 만듭니다. –

+0

@Chris Lutz 사실이지만 언어 디자이너로서 가끔씩 역 호환성을 해소해야합니다. C와 같은 언어를 사용하면 자주 발생하지 않아도되지만 10 년마다 한 번씩 묻습니다. 많은 경우 우리는 당신의 사고 방식으로 인해 좋을지도 모르는 디자인 결정에 매달 렸습니다. – Imagist

19

C 소스를 컴파일 할 때 심볼 이름은 그대로 유지됩니다. 함수 오버로딩을 도입하면 이름 충돌을 막기 위해 이름 변환 기법을 제공해야합니다. 결과적으로, C++과 마찬가지로, 컴파일 된 바이너리에서 심볼 생성 이름을 생성하게됩니다.

또한 C는 엄격한 타이핑을 특징으로하지 않습니다. 많은 것들이 C에서 암묵적으로 서로 변환 가능합니다. 과부하 해결 규칙의 복잡성은 이러한 종류의 언어에서 혼란을 가져올 수 있습니다.

+0

이것에 대한 응답은 간단합니다 : 표준 이름을 mangling하는 기술을 제공하십시오. 형식 정보를 유지합니다. 'foo (bar) -> foo-bar'와'foo (baz) -> foo-baz '같은 것을 구현하는 것은 어렵지 않습니다. – Imagist

+2

나는 실제로 3 점을 언급했다 : 1. 약한 타이핑 2. 복잡성 증가 3. 이름 충돌. 표준 이름 변환 기법을 만들 수 있지만 C89에서 이미 컴파일 된 라이브러리와 어떻게 호환 될 수 있으며 C99에서 라이브러리를 빌드하면 C89에서 어떻게 사용할 수 있습니까? –

6

나를 포함하여 많은 언어 디자이너가 C의 암시 적 프로모션으로 인한 함수 오버로딩이 코드를 이해하기 어렵게 만들 수 있다고 생각합니다. 증거를 얻으려면 C++에 대해 축적 된 지식 체계를 살펴보십시오.

일반적으로 C99은 기존 관행과 크게 호환 될 수있는 적당한 개정판을위한 것입니다. 오버로드는 꽤 큰 출발이었습니다.

+1

필자를 포함하여 많은 언어 디자이너가 포인터를 통해 메모리에 직접 액세스하면 코드를 이해하기가 어려울 수 있다고 생각합니다. 해결책은 분명히 언어에서 포인터를 제외하지 않는 것입니다 (적어도 C의 경우는 제외). – Imagist

+0

@Imagist. 나는 너에게 동의한다. 필자는 포인터 코드를 제어하고 이해하기위한 더 나은 메커니즘을 제공하는 Modula-3에 내 운영 체제를 작성하려고합니다. 그러나 포인터 프로그램이 작성되어야하고, HOPL-II에서 Dennis Ritchie의 기사를 읽은 후에, 나는 C가 그 틈새 시장을 잘 차지하여 결코 대체 될 수 없을 것이라고 믿는다. 하지만 사람들은 응용 프로그램을 작성하는 것을 중단해야합니다! (그리고 Java 덕분에 많은 사람들이 그렇게했습니다.) –

+0

C 암시 적 변환을 사용하면 오버로드없이 코드를 이해하기가 어렵습니다. +1 – SingleNegationElimination

관련 문제