하나의 C 소스 파일을 다른 파일에 포함 하시겠습니까?


답변:


113

적절하게 사용하면 유용한 기술이 될 수 있습니다.

상당히 작은 공용 인터페이스와 재사용 불가능한 구현 코드가 많은 복잡하고 성능이 중요한 하위 시스템이 있다고 가정 해 보겠습니다. 코드는 수천 줄, 백 개 정도의 개인 기능 및 상당한 개인 데이터로 실행됩니다. 사소하지 않은 임베디드 시스템으로 작업하는 경우이 상황을 충분히 자주 처리 할 수 ​​있습니다.

솔루션은 아마도 계층화되고 모듈화되고 분리 될 것이며 이러한 측면은 서브 시스템의 다른 부분을 다른 파일에 코딩하여 유용하게 표현하고 강화할 수 있습니다.

C를 사용하면 이렇게하면 많은 것을 잃을 수 있습니다. 거의 모든 툴체인은 단일 컴파일 단위에 대해 적절한 최적화를 제공하지만 extern으로 선언 된 모든 것에 대해 매우 비관적입니다.

모든 것을 하나의 C 소스 모듈에 넣으면-

  • 성능 및 코드 크기 개선-많은 경우 함수 호출이 인라인됩니다. 인라인 없이도 컴파일러는 더 효율적인 코드를 생성 할 수 있습니다.

  • 링크 레벨 데이터 및 기능 숨기기.

  • 네임 스페이스 오염 및 그에 따른 결과 방지-덜 다루기 힘든 이름을 사용할 수 있습니다.

  • 더 빠른 컴파일 및 연결.

그러나이 파일을 편집 할 때 거룩하지 않게 엉망이되고 함축 된 모듈성을 잃게됩니다. 이는 소스를 여러 파일로 분할하고이를 포함하여 단일 컴파일 단위를 생성함으로써 극복 할 수 있습니다.

그래도 제대로 관리하려면 몇 가지 규칙을 적용해야합니다. 이것들은 어느 정도 도구 체인에 따라 다르지만 몇 가지 일반적인 포인터는 다음과 같습니다.

  • 공용 인터페이스를 별도의 헤더 파일에 넣으십시오. 어쨌든이 작업을 수행해야합니다.

  • 모든 보조 .c 파일을 포함하는 하나의 기본 .c 파일이 있습니다. 여기에는 공용 인터페이스에 대한 코드도 포함될 수 있습니다.

  • 컴파일러 가드를 사용하여 비공개 헤더와 소스 모듈이 외부 컴파일 단위에 포함되지 않도록합니다.

  • 모든 개인 데이터 및 함수는 정적으로 선언되어야합니다.

  • .c 및 .h 파일 간의 개념적 구별을 유지하십시오. 이는 기존 규칙을 활용합니다. 차이점은 헤더에 많은 정적 선언이 있다는 것입니다.

  • 도구 체인에서 그렇게하지 않는 이유가없는 경우 비공개 구현 파일의 이름을 .c 및 .h로 지정합니다. include 가드를 사용하면 코드가 생성되지 않고 새 이름이 도입되지 않습니다 (연결 중에 일부 빈 세그먼트가 생길 수 있습니다). 가장 큰 장점은 다른 도구 (예 : IDE)가 이러한 파일을 적절하게 처리한다는 것입니다.


1
+1 이것은 여전히 ​​현실이지만, 더 나은 컴파일러는 시간이 지남에 따라이 방법을 쓸모 없게 만들 것입니다. 링크 시간 최적화 기능을 갖춘 GCC 4.5는 그 과정에서 큰 진전을 이루었습니다.
u0b34a0f6ae

나는 많은 프로그램이 이런 일을하는 것을 보았고, 그들의 코드를 재사용하려고 할 때 신경이 쓰인다. 왜 그렇게하는지 설명하고 경비원의 사용을 제안 해주셔서 감사합니다 (종종 안 됨).
Joey Adams

C51 용 임베디드 개발에서 extern 및 다중 C 파일을 사용하면 골칫거리 일뿐입니다. 내 시간을 되찾기 위해 하나의 C 파일에 다른 모든 파일이 포함되도록 전환합니다.
mahesh

기록 : GCC는 다양한 번역 단위에 대한 최적화를 지원합니다 . 링크 시간 최적화 에 대한 이 SO 스레드 및 GCC 매뉴얼 섹션을 참조 하세요 .
Twonky

60

괜찮아? 예, 컴파일됩니다

추천합니까? no-.c 파일은 .obj 파일로 컴파일됩니다. obj 파일은 컴파일 후 (링커에 의해) 실행 파일 (또는 라이브러리)로 함께 연결되므로 하나의 .c 파일을 다른 파일에 포함 할 필요가 없습니다. 대신 할 일은 다른 .c 파일에서 사용할 수있는 함수 / 변수를 나열하는 .h 파일을 만들고 .h 파일을 포함하는 것입니다.


14
또한 컴파일하더라도 #included .c 파일도 컴파일되고 두 개체 파일이 함께 연결되면 연결되지 않을 수 있습니다. 다중 정의 된 기호로 끝날 수 있습니다.
Nick Meyer

1
작은 질문입니다. struct + 메서드를 선언하는 헤더 파일과이를 정의하는 해당 .c 파일이 있습니다. 해당 메서드가 구조체를 매개 변수로 사용하는 경우 기본 메서드가 정의 된 다른 .c 파일에 .c 파일을 포함하지 않으려면 어떻게해야합니까?
stdout

12

아니.

빌드 환경 (지정하지 않음)에 따라 원하는 방식으로 정확하게 작동 할 수 있습니다.

그러나 * .c를 컴파일 할 것으로 예상되는 많은 환경 (IDE와 수작업으로 만든 Makefile 모두)이 있습니다.이 경우 중복 기호로 인해 링커 오류가 발생할 수 있습니다.

원칙적으로 이러한 관행은 피해야합니다.

#include 소스를 반드시 사용해야하는 경우 (일반적으로 피해야 함) 파일에 대해 다른 파일 접미사를 사용하십시오.


9

나는 우리 팀이 .c 파일을 포함하기로 결정한 상황을 공유 할 것이라고 생각했습니다. 우리의 아키텍처는 주로 메시지 시스템을 통해 분리 된 모듈로 구성됩니다. 이러한 메시지 핸들러는 공용이며 많은 로컬 정적 작업자 함수를 호출하여 작업을 수행합니다. 이 개인 구현 코드를 실행하는 유일한 방법은 공개 메시지 인터페이스를 통해 간접적으로 수행하는 것이기 때문에 단위 테스트 케이스에 대한 커버리지를 얻으려고 할 때 문제가 발생했습니다. 일부 작업자 기능이 스택에 무릎 깊이 쌓여 있으면 적절한 적용 범위를 달성하는 데 악몽이되었습니다.

.c 파일을 포함하는 것은 우리가 테스트에서 흥미로운 기계의 톱니 바퀴에 접근 할 수있는 방법을 제공했습니다.


6

Linux에서 gcc 컴파일러를 사용하여 하나의 출력에 두 개의 c 파일을 연결할 수 있습니다. 하나는 'main.c'이고 다른 하나는 'support.c'인 두 개의 c 파일이 있다고 가정합니다. 따라서이 둘을 연결하는 명령은

gcc main.c support.c -o main.out

이 두 파일은 단일 출력에 링크됩니다. main.out 출력을 실행하려면 명령은 다음과 같습니다.

./main.out

support.c 파일에 선언 된 main.c에서 함수를 사용하는 경우 extern 스토리지 클래스를 사용하여 main.c에서도 선언해야합니다.


5

파일의 확장자는 대부분의 C 컴파일러에서 중요하지 않으므로 작동합니다.

그러나 메이크 파일 또는 프로젝트 설정에 따라 포함 된 c 파일이 별도의 개체 파일을 생성 할 수 있습니다. 링크 할 때 이중 정의 된 기호로 이어질 수 있습니다.


3

.C 또는 .CPP 파일을 다른 소스 파일에 올바르게 포함 할 수 있습니다. IDE에 따라 일반적으로 포함 할 소스 파일 속성을 확인하여 이중 연결을 방지 할 수 있습니다. 일반적으로 해당 속성을 마우스 오른쪽 단추로 클릭하고 속성을 클릭하고 빌드에서 컴파일 / 연결 / 제외 또는 다른 옵션을 선택 취소 / 선택합니다. 아마도. 또는 프로젝트 자체에 파일을 포함 할 수 없으므로 IDE는 파일이 존재하는지조차 모르고 컴파일을 시도하지 않습니다. 그리고 makefile을 사용하면 컴파일과 링크를 위해 파일을 넣지 않을 것입니다.

편집 : 미안하지만 다른 답변에 대한 답변 대신 답변을 만들었습니다.


1

C 언어는 그런 종류의 #include를 금지하지 않지만 결과 번역 단위는 여전히 유효한 C 여야합니다.

.prj 파일에 어떤 프로그램을 사용하고 있는지 모르겠습니다. "make"또는 Visual Studio 등을 사용하는 경우 독립적으로 컴파일 할 수없는 파일없이 컴파일되도록 파일 목록을 설정해야합니다.


0

C 파일을 다른 파일에 포함시키는 것은 합법적이지만,이 작업을 수행하는 이유와 달성하려는 목표를 정확히 알지 않는 한 권장하지 않습니다.
나는 당신이 당신의 질문 뒤에 커뮤니티가 당신의 목표를 달성하기위한 또 다른 더 적절한 방법을 찾을 수있는 이유를 여기에 게시 할 것이라고 거의 확신합니다 (컨텍스트가 주어진 해결책 일 가능성이 있기 때문에 "거의"에 유의하십시오. ).

그건 그렇고 나는 질문의 두 번째 부분을 놓쳤습니다. C 파일이 다른 파일에 포함되고 동시에 프로젝트에 포함 된 경우 개체를 연결하는 이유가 중복 기호 문제로 끝날 것입니다. 즉, 동일한 기능이 두 번 정의됩니다 (모두 정적이 아닌 경우).


-6

다음과 같이 헤더를 추가해야합니다.

#include <another.c>

참고 : 두 파일 모두 같은 위치에 있어야합니다.

나는 이것을 ATMEGA 마이크로 컨트롤러 용 codevison AVR에서 사용하고 실제로 작동하지만 일반 C 언어 파일에서는 작동하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.