2010-04-13 7 views
15

가능한 중복은 : C# 및 자바와 같은 언어에서
Should C++ eliminate header files?전달 선언이 필요한 이유는 무엇입니까?

를 사용하기 전에 (예를 들어) 클래스를 선언 할 필요가 없습니다. 컴파일러가 코드에서 두 번 통과하기 때문에 올바르게 이해할 수 있습니다. 처음에는 단지 "이용 가능한 정보를 수집"하고 두 번째 것은 코드가 올바른지 확인합니다.

C 및 C++에서 컴파일러는 한 번만 수행하므로 그 당시에는 모든 것을 사용할 수 있어야합니다.

그래서 내 질문은 기본적으로 C 및 C++에서이 방법을 사용하지 않는 이유입니다. 헤더 파일의 필요성을 없애지 않을까요?

+0

C++ 컴파일러가 순차적으로 [즉, 그것은 위에서 아래로 읽을 것입니다 읽습니다 :

그래서, 내 생각 엔 반 옳았다. ...] 언어가 어떻게 작동하는지 그럴 것입니다. 두 번 지나가고 함수 프로토 타입을 살펴 보았으면 좋겠지 만 불행히도 언어가 작동하는 방식이 아닙니다. – Warty

+2

중복 : http://stackoverflow.com/questions/752793 –

+4

C 언어가 기본 기술이 현재보다 훨씬 적은 비용과 훨씬 비싼 30 년 전 표준화되었습니다. 완고한 제안 : 사물의 역사에 대해 조금 배우고 이해합니다. 세상은 엄청나게 바뀌었다. e 결정이 내려졌으며 개발 노력을 결정한 후에도 계속 변경 될 것입니다. 누군가 언젠가는 * "WTF?"를 궁금해 할 것입니다. 귀하의 결정에 대해 .... ;-) – DaveE

답변

39

짧은 대답은 컴퓨팅 파워와 리소스가 C가 정의 된 시간과 자바가 25 년 후에 나왔던 시간 사이에 기하 급수적으로 향상되었다는 것입니다.

긴 않음 ...

컴파일 부의 최대 크기 - 단일 청크 컴파일러 프로세스 코드 블록 - 메모리의 양에 의해 제한 될 것이라는 것을 컴파일 컴퓨터에 있습니다. 입력 한 기호를 기계어 코드로 처리하려면 컴파일러가 조회 표에있는 모든 기호를 보유하고 코드에서 기호를 참조 할 때 참조해야합니다.

C가 1972 년에 만들어 졌을 때 컴퓨팅 리소스는 훨씬 부족하고 높은 프리미엄을받습니다. 복잡한 프로그램의 전체 심볼 테이블을 한 번에 저장하는 데 필요한 메모리는 대부분의 시스템에서 사용할 수 없었습니다. 고정 저장 장치 또한 비싸고 속도가 매우 느 렸기 때문에 가상 메모리와 같은 아이디어 나 디스크상의 기호 테이블의 일부분을 저장하는 것은 합리적인 시간 내에 컴파일을 허용하지 않았습니다.

이 문제를 해결하는 가장 좋은 방법은 코드 테이블의 어느 부분을 미리 컴파일 단위에 넣어야 할지를 인간이 구분하여 코드를 더 작은 조각으로 정리하는 것이 었습니다.프로그래머가 꽤 작은 작업을 부과 할 때 프로그래머는 으로 사용하면 컴퓨터가 프로그래머라면 아무 것도 찾을 수 없다는 엄청난 노력을 덜어 준다 사용할 수 있습니다.

또한 모든 소스 파일에 두 개의 패스를 만들어 내지 않아도 컴파일러가 저장되었습니다. 처음에는 내부의 모든 심볼을 인덱싱하고 두 번째는 참조를 파싱하여 조회합니다. 검색 시간을 초 단위로 측정하고 읽기 처리량을 초당 바이트 수 (킬로바이트 또는 메가 바이트가 아님)로 측정 한 자기 테이프를 다루는 경우 상당히 의미가있었습니다.

C++은 거의 17 년 후에 생성되었지만 C의 수퍼 세트로 정의되었으므로 동일한 메커니즘을 사용해야했습니다.

자바가 1995 년에 출시 된 이래로 평균 컴퓨터는 복잡한 프로젝트의 경우에도 상징적 인 테이블을 보유하는 데 충분한 메모리가 있었지만 더 이상 큰 부담이되지 않았습니다. 자바는 C와 하위 호환성을 갖도록 설계되지 않았으므로 레거시 메커니즘을 채택 할 필요가 없었습니다. C#도 비슷하게 방해받지 않았습니다.

결과적으로 설계자는 컴파일 작업의 총 비용에 비례하여 비용이 최소화 되었기 때문에 기호 선언을 구획화하는 부담을 프로그래머로부터 다시 컴퓨터로 옮기기로 결정했습니다.

+7

우수 요약. 두 개의 플로피 드라이브에서 C 프로그램을 컴파일하는 "좋은 옛날"을 생각 나게합니다. 640K PC - 여섯 개 또는 그 이상의 플로피 변경으로 약 10 분이 걸렸습니다. 몇 백 문장 이상을 포함하는 프로그램을위한 모든 것! 그리고 저는 그 모든 힘으로 천국에 있다고 생각했습니다. – NealB

+4

좋은 답변, 우리는 젊은 사람들을위한 역사적인 전망을 얻는 것이 좋습니다! –

5

결론 : 전방 선언을 필요로하지 않는 컴파일러 기술의 발전이있었습니다. 플러스 컴퓨터는 수천 배 더 빠르므로 앞으로 선언이 부족한 상황을 처리하는 데 필요한 추가 계산을 할 수 있습니다.

C 및 C++은 모든 CPU주기를 저장해야 할 때 더 오래되어 표준화되었습니다.

+2

:-) 즉, C#은 C++보다 낫습니다. –

+8

여기에 핵심 단어가 누락되었습니다 : 이전 버전과의 호환성. 마지막 라인은 C와 C처럼 소리가 나고, 돌기 시대의 표준 버전은 단 하나뿐입니다. 그것은 "처음 * 표준화되었고 ... 이전 버전과의 호환성을 유지하기 위해서는이 방법이 동일하게 유지되어야합니다." @ 프랜시 : C#으로 OS 작성을 마쳤 으면 저를 데려 오십시오. – GManNickG

+3

@Franci : 아니요 ... 다른 말로하면, 현대 언어 컴파일러는 하위 호환성에 대해 걱정할 필요가 없으므로 앞으로 선언을 폐기했습니다. 그것은 C++로 할 수 있습니다. 재미있는 C# 버드로 하드웨어 드라이버를 작성하십시오. –

1

이것은 C/C++에서 더 작은 컴파일 모듈 때문입니다. C/C++에서 각 .c/.cpp 파일은 별도로 컴파일되어 .obj 모듈을 만듭니다. 따라서 컴파일러는 다른 컴파일 모듈에서 선언 된 유형 및 변수에 대한 정보가 필요합니다. 이 정보는 일반적으로 헤더 파일에 전달 선언 형식으로 제공됩니다.

C#은 한 번에 하나의 큰 컴파일 모듈로 여러 .cs 파일을 컴파일합니다.

사실 C# 프로그램에서 다른 컴파일 된 모듈을 참조 할 때 컴파일러는 C++ 컴파일러와 동일한 방식으로 선언 (형식 이름 등)을 알아야합니다. 이 정보는 컴파일 된 모듈에서 직접 가져옵니다. C++에서는 동일한 정보가 명시 적으로 분리되어 있으므로 (C++에서 컴파일 된 DLL에서 변수 이름을 찾을 수 없지만 .NET 어셈블리에서 결정할 수 있습니다).

+0

불행히도 C#이 수천 개의 소스 파일과 C++이 관리하는 것보다 수백만 줄의 코드를 포함하는 100 개짜리 솔루션을 관리하는 방법을 설명하지 못합니다.h 파일 (필요로하는 모든 정보가 하나의 파일에 있음에도 불구하고 앞으로 선언이 필요할 수도 있음). –

+0

@ Jason : 개별 컴파일의 이점은 다릅니다. 구현 만 변경하면 재 컴파일이 거의 즉시 이루어집니다. (물론 이것은 처음 컴파일을 더 느리게 만든다.) 왜 C++이 하나의 헤더 파일을 관리 할 수 ​​없는지 모르겠다. 나는 결코 내 문제가 발생하지 않았다. – Vlad

+0

@Vlad : 당신은 "... 컴파일러는 다른 컴파일 모듈에서 선언 된 타입에 대한 정보가 필요합니다"라고 말했지만 사실 단일 헤더의 단일 C++ 클래스도 미리 선언을 요구할 수 있습니다 - 즉 하나의 컴파일 모듈 내에서도 가능합니다 . 즉, C++은 코드를 선형 방식으로 파싱하므로 (참조 할 때 미래 타입에 대한 사전 선언이 필요함) C#은 모든 유형에 무작위로 액세스 할 수있는 코드베이스 데이터베이스를 효과적으로 만듭니다. –

0

C++의 forward 선언은 현재 컴파일 된 소스가 컴파일러에 사용할 수있는 다른 코드 조각에 대한 메타 데이터를 제공하여 올바른 코드를 생성 할 수있는 방법입니다.

해당 메타 데이터는 링크 된 라이브러리/구성 요소 작성자가 제공 할 수 있습니다. 그러나 자동으로 생성 될 수도 있습니다 (예를 들어 COM 개체에 대한 C++ 헤더 파일을 생성하는 도구가 있음). 어쨌든 메타 데이터를 표현하는 C++ 방식은 소스 코드에 포함해야하는 헤더 파일을 사용하는 것입니다.

C#/Net은 컴파일시에도 유사한 메타 데이터를 사용합니다. 그러나 해당 메타 데이터는 적용 대상 어셈블리가 빌드되고 일반적으로 해당 메타 데이터에 포함될 때 자동으로 생성됩니다. 따라서 C# 프로젝트에서 어셈블리를 참조하면 컴파일러에게 "이 어셈블리에서도 필요한 메타 데이터를 찾습니다."라고 말합니다.

즉, C#의 메타 데이터 생성 및 사용은 개발자에게 더 투명하므로 개발자가 자신의 코드 작성에 중점을 둘 수 있습니다.

어셈블리와 함께 번들로 제공되는 코드에 대한 메타 데이터를 갖는 다른 이점도 있습니다. 반사, 코드 방출, on-the-fly 직렬화 - 이들은 모두 런타임에 적절한 코드를 생성 할 수 있도록 메타 데이터에 의존합니다.

이 C++ 아날로그는 호환되지 않는 구현으로 널리 채택되지는 않았지만 RTTI입니다.

에릭 Lippert의, C#을 내부 만물의 블로거에서
0

: http://blogs.msdn.com/ericlippert/archive/2010/02/04/how-many-passes.aspx 다음 사용자가 다시이 영향을 가지고

는 C는 # 언어 선언 용도 전에 발생하지 않아도, 하고, 컴파일러 작성자. [...]

컴파일러 작성자에게 미치는 영향은 "2 패스" 컴파일러가 있어야하는 입니다. 첫 번째 단계에서는 선언과 본문 무시에 대해 으로 보입니다.우리는 우리가 C++의 헤더에서 가져온 것 것을 선언에서 모든 정보를 수집 한 후 , 우리는 코드를 통해 두 번째 패스를 타고 몸의 IL를 생성합니다.

요약하면 C#에서는 C#에서는 선언 할 필요가 없습니다. 이는 C++에서 명시 적으로 선언해야 함을 의미하며 헤더 파일을 사용하여보다 편리하고 안전하게 수행하므로 One Definition Rule을 위반하지 않아야합니다.

3

아니요, 헤더 파일을 제거하지 않을 것입니다. 동일한 파일에서 클래스/함수를 선언 할 때 헤더를 사용하지 않아도됩니다. 헤더의 가장 큰 이유는 이 아니기 때문에 동일한 파일에있는 내용을 선언하는 데는이 아닙니다. 헤더의 주된 이유는 기타 파일에 정의 된 것을 선언하는 것입니다.

C (및 C++)의 의미 규칙은 "단일 단계"스타일 동작을 요구합니다. 그냥 예를 들어, 다음과 같은 코드를 고려하십시오 글로벌

int i; 

int f() { 
    i = 1; 
    int i = 2; 
} 

i=1 양수인, 하지f()의 내부에 정의 된 하나. 이는 할당 시점에 i의 로컬 정의가 아직 보이지 않았기 때문에 고려되지 않았기 때문입니다. 당신은 여전히 ​​2 패스 컴파일러로 이러한 규칙을 따를 수 있지만 그렇게하는 것은 결코 쉬운 일이 아닙니다. 필자는 스펙을 확인하지 않았지만 Java와 C#은 C 및 C++과 다르다는 것을 당연시합니다.

편집 : 의견에 내 추측이 잘못되었다고했기 때문에 약간 확인했습니다. 자바 언어 참조 설명서에 따르면, §14.4.2, 자바 (++ 가까운 C와 같은 규칙을 조금 다른 을 따르는 것,하지만 훨씬.

나는 C# language specification을, (읽기 이상으로 경고 : Word 파일) 그러나 입니다. (§7.7.1)은 다음과 같이 말합니다 : "지역 변수 선언 (§8.5.1)에서 선언 된 지역 변수의 범위는 선언 발생합니다. "

이것은 C#에서 로컬 변수가 블록 전체에 표시되어야한다고 나타내며, 예를 들어 비슷한 코드를 사용하면 assignme이 선언됩니다 nt는 전역 변수가 아닌 지역 변수입니다. 자바는이 점에서 C로 (꽤 much0 같은 규칙을 ++ 다음,하지만 C#을하지 않습니다

+0

당신의 추측은 정확하지 않을 것입니다. –

관련 문제