2009-02-10 7 views
5

저는 보통 경험이 풍부한 Java/C# 프로그래머이며 최근에 C++를 배우기 시작했습니다. 문제는 다양한 헤더 및 코드 파일을 구조화하는 방법을 이해하는 데 문제가 있다는 것입니다. 이것은 대부분 컴파일러가 모든 것을 연결하는 방법에 대한 이해가 부족하기 때문에 발생합니다. 나는 약간의 교과서를 읽으려고 노력했지만 나의 선입관은 나의 자바와 C# 지식에 의해 심하게 착색되어있다. 예를 들어 클래스 정의가 아닌 네임 스페이스에서 메서드 등을 정의 할 수 있다는 사실을 알기가 힘듭니다.Java/C# 관점에서 C++ 컴파일러 이해하기

많은 C++ -> Java/C# 가이드가 있지만 실제로는 다른 방법이 없습니다. Java/C# -> C++로 쉽게 전환 할 수있는 좋은 리소스가 있습니까? 특히 컴파일 프로세스를 이해하는 데 도움이됩니까?

+0

편집 : 모든 응답 덕분에 모든 대답이 유용하고 유익했습니다. – Whatsit

+0

비슷한 상황에서이 페이지가 특히 유용하다는 것을 알았습니다. 특히 A3.3 (클래스) 섹션 : http://www.horstmann.com/ccj2/ccjapp3.html – Whatsit

답변

4

C++ FAQ은 C++의 모든 고유 한 특성에 대한 훌륭한 자료이지만 찾고있는 것보다 조금 더 발전했을 것입니다. 대부분의 질문은 대답뿐만 아니라 공정하게 숙련 된 C++ 개발자에게도 신비가 있습니다 .

Google C++ 자습서를 사용하면 뭔가를 찾을 수있을 것입니다. 어셈블리 언어를 배우려는 시도 (또는 최소한 마이크로 프로세서에서 실제로 일어나는 일에 대한 간단한 소개)를 해보고 싶을 수도 있습니다. C 및 C++ 모두 하드웨어와 매우 비슷하기 때문입니다. 자바의 속도와 힘은 어디에서 유래되었지만, Java가 제공하는 더 멋진 추상화의 대가로 제공됩니다.

위의 질문에 대한 답변을 시도해 볼 수는 있지만 잘 할 수는 없습니다.

헤더 파일과 cpp 파일 간의 관계를 이해하는 열쇠 중 하나는 "번역 단위"의 개념을 이해하는 것입니다. Java 클래스 파일은 이진 형식으로 컴파일되는 기본 단위이기 때문에 변환 단위로 간주 될 수 있습니다. C++에서 거의 모든 cpp 파일은 번역 단위입니다 (이상한 일을하는 경우 예외가 있습니다).

헤더 파일은 여러 번역 단위에 포함될 수 있으며 헤더에 정의 된 내용을 사용하는 모든 곳에 포함되어야합니다. #include 지시어는 말 그대로 텍스트 대체를 수행합니다. 포함 된 파일의 내용은 #include 지시어가 그대로 삽입됩니다. 일반적으로 클래스 인터페이스를 헤더 파일에 정의하고 cpp 파일에 구현을 정의하려고합니다. 헤더를 포함 할 수있는 다른 번역 단위에 구현 세부 사항을 공개하고 싶지 않기 때문입니다. C++에서 클래스를 포함한 모든 것은 실제로 풍부한 개체가 아니라 컴파일러가 의미를 할당하는 메모리 덩어리입니다 ... 각 번역 단위에 동일한 헤더 정보를 컴파일하면 컴파일러에서 모든 번역 단위에 기억의 덩어리가 무엇을 나타내는 지에 대한 동일한 이해. 컴파일 시간 후 풍부한 데이터가 없기 때문에 리플렉션과 같은 일은 불가능합니다.

C++ 빌드 프로세스의 두 번째 단계는 링커가 컴파일 된 모든 번역 단위를 가져 와서 번역 단위에서 사용되었지만 정의되지 않은 기호 (대개 함수 호출과 변수)를 찾는 링킹입니다. 그런 다음 심볼을 정의하고 함께 링크하는 다른 번역 단위를 찾아 특정 함수에 대한 모든 호출이이를 정의하는 번역 단위로 연결되도록합니다.

클래스 메서드의 경우 클래스 인스턴스를 통해 호출해야합니다. 클래스 인스턴스는 메모리 조각에 대한 포인터입니다. 컴파일러에서 이러한 유형의 메서드 호출을 발견하면 함수를 호출하는 코드를 출력하여 this 포인터라고하는 포인터를 암시 적으로 첫 번째 인수로 함수에 전달합니다. 링커에는 클래스 개념이 없으므로 클래스에 속하지 않는 함수를 가질 수 있습니다 (메서드는 클래스의 멤버 함수이므로 적절하게 클래스가 없으므로 메서드가 아닙니다. 함수를 정의하는 변환 단위와 함수를 호출하고 함께 묶는 변환 단위를 볼 수 있습니다.

예상보다 훨씬 길어졌지만 당연히 지나치게 단순화 된 것이지만, 내 지식과 세부 수준까지는 정확합니다 ... 일부가 도움이되기를 바랍니다. 적어도 그것은 당신에게 어떤 인터넷 검색을위한 출발점을 제공해야합니다.

4

처음 C를 사용하기 시작했을 때 혼란 스러웠습니다. 책은 머리글과 코드 파일의 올바른 사용을 기술하는 훌륭한 작업을 수행하지 않습니다.

컴파일러는 각 .cpp 파일을로드하고 다른 모든 .cpp 파일과 독립적으로 컴파일하여 작동합니다. 컴파일의 첫 번째 단계는 #include 문이 참조하는 모든 헤더를로드하는 것입니다. #include "foo.h"가있을 때마다 foo.h 전체를 텍스트로 삽입한다고 생각할 수 있습니다.

파일 구성 방법에 대한 의미는 무엇입니까? 헤더 파일에는 다른 .cpp 파일을 참조하는 데 필요한 프로그램 부분이 있어야합니다. 일반적으로 구현은 헤더 파일에 있어서는 안됩니다. 이로 인해 문제가 발생합니다. 헤더 파일에는 클래스, 함수 및 전역 변수 (사용해야하는 경우)의 선언이 포함되어야합니다.

+0

"헤더 파일은 클래스 선언을 포함해야합니다."사실헤더 파일에 멤버 함수를 정의하고 선언합니다. 그러나 * 멤버 함수/정적 멤버를 정의하는 것은 소스 파일에서 수행됩니다 . 동안, 클래스 foo; 는 decleration 클래스 foo {} 정의입니다. –

1

실제로 C++ 컴파일러에 대한 설명과 C 컴파일러에서 설명을 보는 것이 좋습니다. 내 경험상 이것들은 더 잘 설명되며 OOP 문제로 혼란을 피할 수 있습니다. C 컴파일에 대한 자료를 찾으십시오. 나는 당신을 나의 모교에서 훌륭한 슬라이드 소책자로 당신을 추천했을 것입니다, 그러나 그것은 영어가 아닙니다.

C 컴파일과 Java/C#의 주된 차이점은 컴파일이 확인 된 엔티티를 만들지 않는다는 것입니다. 즉, Java로 컴파일하면 컴파일러는 참조 된 클래스에 대해 이미 컴파일 된 클래스 파일을 찾고 모든 것이 사용 가능하고 일관성이 있는지 확인합니다. 기본 가정은 결국 프로그램을 실행할 때 해당 파일도 사용할 수 있다는 것입니다.

반면에 컴파일 된 C 파일은 "약속"일뿐입니다. 의존성이 어떻게 보이는지 (함수 선언의 형태로) 선언에 의존하지만, 이것이 어디에서나 정의된다는 보장은 없습니다. 가장 어려운 마인드 스위치는 C 파일을 그 파일로 생각하는 것이 아니라 그 파일에 포함 된 모든 것 (즉, 전처리 기가 생성하는 것)과 함께 집계하는 것입니다. 즉, 컴파일러는 헤더 파일을 보지 못합니다. 하나의 큰 파일처럼 보입니다. 컴파일러는 생성 된 객체 파일에서 "아직없는 것"을 추적합니다. 나중에 링크 타임에 링커는 다른 오브젝트 파일의 자료로 모든 공백을 채우려고하여이를 해결합니다.

1

당신은 왜 컴파일과 링크가 분리되어 있는지 알고 싶을지도 모릅니다. 왜냐하면 나는 그것을 설명하는 게시물을 보지 못했고, 사물의 근본적인 이유를 알지 못하는 많은 혼란의 원인입니다.

라이브러리 호출의 필요성 때문에 (그리고 여러 이유가있을 수 있기 때문에) 링크 및 컴파일이 별도로 완료됩니다. 정의한 경우 또는 그 ilk 중 하나라도 해당 헤더에 함수 프로토 타입을 구현하는 코드는 이미 컴파일되어 어딘가에 객체 코드로있는 libary의 일부입니다. 커다란 컴파일 프로세스가 대신 사용된다면 라이브러리 호출을위한 소스가 있어야 할뿐만 아니라 라이브러리 코드를 컴파일하기 때문에 컴파일하는 데 더 많은 시간이 필요합니다.