#pragma가 자동으로 가정되지 않는 이유는 무엇입니까? 한 번만 포함하도록

파일을 한 번만 포함하도록 컴파일러에 구체적으로 말하는 이유는 무엇입니까? 기본적으로 말이되지 않습니까? 단일 파일을 여러 번 포함해야하는 이유가 있습니까? 왜 그것을 가정하지 않습니까? 특정 하드웨어와 관련이 있습니까?



답변

여기에 여러 관련 질문이 있습니다.

  • #pragma once자동으로 시행되지 않는 이유는 무엇 입니까?
    파일을 두 번 이상 포함하려는 상황이 있기 때문입니다.

  • 파일을 여러 번 포함하려는 이유는 무엇입니까?
    다른 답변에는 여러 가지 이유가 있습니다 (Boost. Preprocessor, X-Macros, 데이터 파일 포함). “코드 중복 방지”의 특정 예를 추가하고 싶습니다. OpenFOAM#include함수 내에서 비트와 조각을 공통 개념으로 사용 하는 스타일을 권장합니다 . 예를 들어이 토론을 참조하십시오 .

  • 좋아,하지만 왜 옵트 아웃이 기본값이 아닌가?
    실제로 표준에 지정되어 있지 않기 때문입니다. #pragma는 정의상 구현 특정 확장입니다.

  • #pragma once널리 지원되는 기능이므로 아직 표준화 된 기능 이 되지 않은 이유는 무엇 입니까?
    플랫폼에 구애받지 않는 방식으로 “동일한 파일”을 고정하는 것은 실제로 놀랍도록 어렵 기 때문입니다. 자세한 내용은이 답변을 참조하십시오 .


답변

함수 내부와 같이 전역 범위뿐만 아니라 파일의 #include 모든 위치 에서 사용할 수 있습니다 (필요한 경우 여러 번). 물론, 추악하고 좋지 않은 스타일이지만 가능하고 때로는 합리적입니다 (포함하는 파일에 따라 다름). 경우는 #include오직 다음 한 번 일이없는 것 일이었다. #include결국 멍청한 텍스트 대체 (잘라 내기 및 붙여 넣기)를 수행하고 포함하는 모든 것이 헤더 파일 일 필요는 없습니다. 예를 들어 #include, 원시 데이터를 포함하는 자동 생성 데이터가 포함 된 파일을 std::vector. 처럼

std::vector<int> data = {
#include "my_generated_data.txt"
}

그리고 “my_generated_data.txt”는 컴파일 중에 빌드 시스템에 의해 생성 된 것입니다.

또는 내가 게으르고 / 어리 석고 / 멍청해서 이것을 파일에 넣을 수도 있습니다 ( 매우 인위적인 예) :

const noexcept;

그리고 나는

class foo {
    void f1()
    #include "stupid.file"
    int f2(int)
    #include "stupid.file"
};

약간 덜 고안된 또 다른 예는 많은 함수가 네임 스페이스에서 많은 양의 유형을 사용해야하는 소스 파일이 될 것입니다.하지만 using namespace foo;전역 네임 스페이스를 다른 많은 것들로 오염시킬 수 있기 때문에 전역 적으로 말하고 싶지는 않습니다. 당신은 원하지 않습니다. 따라서 다음을 포함하는 “foo”파일을 만듭니다.

using std::vector;
using std::array;
using std::rotate;
... You get the idea ...

그런 다음 소스 파일에서이 작업을 수행합니다.

void f1() {
#include "foo" // needs "stuff"
}

void f2() {
    // Doesn't need "stuff"
}

void f3() {
#include "foo" // also needs "stuff"
}

참고 : 나는 이와 같은 일을 옹호하지 않습니다. 그러나 가능하고 일부 코드베이스에서 수행되며 왜 허용되지 않아야하는지 모르겠습니다. 그것은 않습니다 그 용도가있다.

또한 포함하는 파일이 특정 매크로 ( #defines) 의 값에 따라 다르게 동작 할 수도 있습니다 . 따라서 먼저 일부 값을 변경 한 후 여러 위치에 파일을 포함 할 수 있으므로 소스 파일의 다른 부분에서 다른 동작을 얻을 수 있습니다.


답변

여러 번 포함하는 것은 예를 들어 X- 매크로 기술을 사용하여 사용할 수 있습니다 .

data.inc :

X(ONE)
X(TWO)
X(THREE)

use_data_inc_twice.c

enum data_e {
#define X(V) V,
   #include "data.inc"
#undef X
};
char const* data_e__strings[]={
#define X(V) [V]=#V,
   #include "data.inc"
#undef X
};

다른 용도에 대해서는 잘 모릅니다.


답변

언어에 존재하는 “#include”기능의 목적은 프로그램을 여러 컴파일 단위로 분해하는 지원을 제공하는 것이라는 가정하에 작동하는 것 같습니다. 그것은 틀 렸습니다.

그 역할을 수행 할 수는 있지만 의도 된 목적은 아닙니다. C는 원래 Unix를 다시 구현하기 위해 PDP-11 Macro-11 Assembly 보다 약간 높은 수준의 언어로 개발 되었습니다 . 그것은 Macro-11의 기능이기 때문에 매크로 전처리기를 가지고있었습니다. 다른 파일의 매크로를 텍스트로 포함 할 수있는 기능이 있었는데, 이는 그들이 새로운 C 컴파일러로 포팅하는 기존 유닉스가 사용했던 Macro-11의 기능 이었기 때문입니다.

이제 “#include”는 코드를 컴파일 단위로 분리하는 데 유용 하다는 것이 밝혀졌습니다 . 그러나이 해킹이 존재한다는 사실은 C로 수행되는 방법이되었음을 의미합니다. 방법이 존재한다는 사실 은이 기능을 제공하기 위해 새로운 방법 을 만들 필요 가 없음을 의미 하므로 더 안전한 것은 없습니다 (예 : 다중 공격에 취약하지 않음). -포함)이 생성되었습니다. 이미 C에 있었기 때문에 나머지 C 구문 및 관용구 대부분과 함께 C ++로 복사되었습니다.

C ++ 에 적절한 모듈 시스템 을 제공하기위한 제안 이있어이 45 년 된 전 처리기 해킹을 마침내 생략 할 수 있습니다. 이것이 얼마나 임박한지 모르겠습니다. 나는 그것이 10 년 넘게 작동하고 있다는 이야기를 들었습니다.


답변

아니오, 이것은 예를 들어 도서관 작성자가 사용할 수있는 옵션을 크게 방해합니다. 예를 들어 Boost.Preprocessor를 사용하면 전 처리기 루프를 사용할 수 있으며이를 달성하는 유일한 방법은 동일한 파일을 여러 개 포함하는 것입니다.

그리고 Boost.Preprocessor는 매우 유용한 많은 라이브러리를위한 빌딩 블록입니다.


답변

제가 주로 작업하는 제품의 펌웨어에서 함수와 전역 / 정적 변수가 메모리에 할당되어야하는 위치를 지정할 수 있어야합니다. 실시간 처리는 프로세서가 직접 빠르게 액세스 할 수 있도록 칩의 L1 메모리에 있어야합니다. 덜 중요한 처리는 L2 메모리 온 칩에서 진행될 수 있습니다. 특히 신속하게 처리 할 필요가없는 것은 외부 DDR에 상주하여 캐싱을 통과 할 수 있습니다. 조금 느려도 문제가되지 않기 때문입니다.

일이 진행되는 위치를 할당하는 #pragma는 길고 사소한 줄입니다. 오해하기 쉬울 것입니다. 잘못을 얻기의 효과는 코드 / 데이터가 자동으로 기본에 (DDR) 메모리를 넣어 것, 그리고 효과가 있다는 것 그이 쉽게 알 수없는 이유로 작동 중지 제어 루프 폐쇄 될 수 있습니다.

그래서 저는 그 pragma 만 포함하는 include 파일을 사용합니다. 내 코드는 이제 다음과 같습니다.

헤더 파일 …

#ifndef HEADERFILE_H
#define HEADERFILE_H

#include "set_fast_storage.h"

/* Declare variables */

#include "set_slow_storage.h"

/* Declare functions for initialisation on startup */

#include "set_fast_storage.h"

/* Declare functions for real-time processing */

#include "set_storage_default.h"

#endif

그리고 소스 …

#include "headerfile.h"

#include "set_fast_storage.h"

/* Define variables */

#include "set_slow_storage.h"

/* Define functions for initialisation on startup */

#include "set_fast_storage.h"

/* Define functions for real-time processing */

헤더에만 동일한 파일이 여러 개 포함되어 있음을 알 수 있습니다. 지금 뭔가를 잘못 입력하면 컴파일러가 “set_fat_storage.h”포함 파일을 찾을 수 없다는 메시지를 표시하고 쉽게 수정할 수 있습니다.

따라서 귀하의 질문에 대한 대답으로 이것은 다중 포함이 필요한 실제적이고 실용적인 예입니다.