C/C++의 "#pragma once"가 ISO 표준이 아닌 이유는 무엇입니까?
저는 지금 큰 프로젝트를 하고 있는데, 경비원을 포함한 모든 것을 유지하는 것이 저를 미치게 해요!손으로 쓰는 것은 답답한 시간 낭비입니다.많은 편집자가 가드 포함을 생성할 수 있지만 이는 큰 도움이 되지 않습니다.
Editor는 파일 이름을 기반으로 가드 기호를 생성합니다.이 문제는, 같은 파일명을 가지는 헤더가 다른 디렉토리에 있는 경우에 발생합니다.둘 다 가드를 포함해서 같은 점수를 받을 것이다.디렉토리 구조를 guard 심볼에 포함시키는 것은 매크로의 슬래시와 백슬래시는 최선이 아니기 때문에 에디터의 세련된 접근법이 필요합니다.
파일 이름을 변경해야 할 경우 모든 포함 가드 이름도 변경해야 합니다(ifndef에서 endif 주석 정의 및 이상적).짜증나는.
프리프로세서는 수많은 기호들로 가득 차서 무슨 뜻인지 알 수 없다.
그럼에도 불구하고 정의가 한 번 포함되면 컴파일러는 헤더 포함을 충족할 때마다 헤더를 엽니다.
네임스페이스나 템플릿에는 가드를 사용할 수 없습니다.사실 그들은 네임스페이스를 파괴하고 있어요!
당신의 가드 기호가 독특하지 않을 가능성이 있습니다.
프로그램이 단일 디렉토리에 1000개 미만의 헤더를 포함할 때는 이러한 솔루션이 적합했을 수 있습니다.근데 요즘은?옛날 얘기지 현대의 코딩 습관과는 아무 상관이 없어가장 신경이 쓰이는 것은 이 문제는 #pragma가 지시하면 거의 완벽하게 해결될 수 있다는 것입니다.왜 표준이 아닐까요?
「 」등의 #pragma once
명확한 이점을 가진 완전히 휴대 가능한 방법으로 정의하는 것은 간단한 일이 아닙니다. 중 는 을 지원하는 않습니다.C
단순한 방법으로 정의하면 기존 가드(guard)에 비해 아무런 이점이 없을 수 있습니다.
이 「」를 검출했을 .#pragma once
파일 내용을 다시 포함하지 않도록 하려면 이 파일을 어떻게 식별해야 합니까?
분명한 답은 시스템 상의 파일 고유 위치입니다.시스템에 모든 파일에 대해 고유한 위치가 있지만 많은 시스템이 링크(심링크 및 하드링크)를 제공하므로 파일에는 고유한 위치가 없습니다.파일이 다른 이름으로 검색되었다고 해서 다시 포함시켜야 합니까?아마 아닐 것입니다.
이제 생겼는데, 그 할 수 요? 어떻게 이러한 동작을 정의하는 것이 가능합니까?#pragma once
심볼링크는 말할 것도 없고 디렉토리조차 없는 플랫폼도 모든 플랫폼에서 정확한 의미를 가지며, 심볼링크가 있는 시스템에서 바람직한 동작을 할 수 있습니다.
에 ID가 ID가 정해집니다.따라서 포함된 파일에#pragma once
그리고 정확히 동일한 내용을 가진 파일이 포함되며, 그 다음 두 번째 이후의 파일이 포함됩니다.#include
는 영향을 미치지 않습니다.
이것은 정의하기 쉽고 의미론도 잘 정의되어 있습니다.또한 파일 시스템 링크를 지원 및 사용하는 시스템에서 사용하지 않는 시스템으로 프로젝트를 이동해도 동일하게 작동합니다.
마다 인크루드 파일이 표시됩니다.#pragma once
은 다른 .#pragma once
이미 포함되어 있습니다., '먹다'를 사용하는 것과 한 퍼포먼스 합니다.#include
컴파일러 라이터에 상당한 부담을 줍니다.물론 이 결과는 캐시될 수 있지만 기존의 가드도 마찬가지입니다.
기존의 인크루드 가드는 프로그래머가 인크루드 파일의 고유 식별자인 매크로를 선택하도록 강요하지만, 적어도 동작은 잘 정의되어 있고 구현하기 쉽습니다.
못한 것은.#pragma once
.
include guards는 확실히 귀찮은 일이며, C는 원래 헤더가 기본적으로 1회 포함되도록 설계되어 있어야 합니다.따라서 헤더를 여러 번 포함하는 특별한 옵션이 필요합니다.
하지만, 그렇지 않았고, 당신은 대부분 인크루드 가드를 사용해야만 했다. 할 수 없다#pragma once
매우 폭넓게 서포트되고 있기 때문에, 그럭저럭 사용할 수 있을지도 모릅니다.
개인적으로 저는 인크루드가드에 GUID를 추가하여 당신의 첫 번째 문제(같은 이름의 인크루드 파일)를 해결합니다.그것은 추하고, 대부분의 사람들은 그것을 싫어합니다(그래서 저는 종종 그것을 직장에서 사용하지 않을 수 밖에 없습니다). 하지만 당신의 경험은 그 아이디어가 가치가 있다는 것을 보여줍니다. - 비록 끔찍할 정도로 못생겼다고 해도요. - 하지만 가드를 포함한 전체는 일종의 해킹입니다. - 왜 통째로 하지 않습니까?:
#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
// blah blah blah...
#endif
컴파일러는 가드가 포함된 헤더 파일을 실제로 다시 열지 않는다고 들었습니다(이디옴을 인식하는 법을 배웠습니다).그것이 사실인지(또는 어느 정도 사실인지) 확실하지 않다.재본 적이 없어요.저도 별로 걱정하지 않지만, 제 프로젝트가 그렇게 크지는 않아서 문제가 되고 있어요.
나의 GUID 해킹은 아이템 1, 5, 6을 거의 해결한다.저는 2번, 3번, 4번 아이템만 가지고 살아요.실제로 항목 2의 경우 파일 이름을 변경할 때 포함 가드 매크로의 이름을 바꾸지 않아도 GUID가 고유함을 보장할 수 있습니다.사실 파일 이름을 GUID에 포함할 이유가 전혀 없습니다.하지만 난 알아 - 내 생각에, 전통.
- 이 프로젝트에 포함 파일을 얼마나 자주 추가해야 합니까?가드에 DIRNAME_FILNAME을 추가하는 것이 그렇게 어려운가요?그리고 항상 GUID가 있습니다.
- 정말 그렇게 자주 파일 이름을 바꾸나요?가드를 #endif에 넣는 것은 다른 쓸데없는 댓글과 마찬가지로 짜증난다.
- 1000 헤더 파일 가드 정의가 시스템 라이브러리(특히 Windows)에 의해 생성되는 정의 수보다 적은 비율인지 의심됩니다.
- MSC 10 for DOS(20년 이상 전)는 어떤 헤더가 포함되어 있는지, 또 포함되었을 경우 가드가 포함되어 있는지 추적하고 있었다고 생각합니다.이건 오래된 기술이야
네임스페이스와 템플릿은 헤더를 확장하지 않아야 합니다.설마 이런 짓을 하는 건 아니겠지?
template <typename foo> class bar { #include "bar_impl.h" };
이미 말했잖아요.
이미 기술한 바와 같이 C++ Standard는 다양한 개발 플랫폼을 고려해야 합니다.이들 플랫폼 중 일부는 #pragma를 구현할 수 없게 하는 제한이 있을 수 있습니다.
한편, 이전에는 같은 이유로 스레드 지원이 추가되지 않았지만, 새로운 C++ 규격에는 스레드가 포함되어 있습니다.후자의 경우 매우 제한된 플랫폼을 위해 교차 컴파일할 수 있지만, 개발은 완전한 플랫폼에서 이루어집니다.GCC는 이 확장을 지원하므로 이 기능을 C++ Standard에 푸시하는 데 관심이 없는 것이 질문에 대한 진정한 답변이라고 생각합니다.
실제적인 관점에서 보면 #pragma가 지시했던 것보다 가드를 포함시키는 것이 우리 팀에 더 큰 문제를 일으켰습니다.예를 들어 include guard의 GUID는 파일이 중복되고 나중에 두 복사본이 모두 포함된 경우 도움이 되지 않습니다.중복 정의 오류가 발생하여 소스 코드를 통합하는 데 시간이 걸릴 수 있는 경우 #pragma만 사용합니다.그러나 include guard의 경우 문제를 포착하기 위해 런타임 테스트가 필요할 수 있습니다. 예를 들어 함수 파라미터에 대한 기본 인수가 다른 경우 이 문제가 발생합니다.
나는 인크루드 가드를 사용하는 것을 피한다.#pragma를 지원하지 않는 컴파일러에 코드를 포팅해야 하는 경우 모든 헤더 파일에 include guards를 추가하는 스크립트를 작성합니다.
이 문제는, 같은 파일명을 가지는 헤더가 다른 디렉토리에 있는 경우에 발생합니다.
두 개의 헤더가 있는데 둘 다ice_cream_maker.h
당신의 프로젝트에서, 두 가지 모두라고 불리는 클래스가 있습니다.ice_cream_maker
정의되어 있는 것은 같은 기능을 수행하는 것입니까?아니면 시스템 내의 모든 클래스에 전화를 걸고 있습니까?foo
?
그럼에도 불구하고 정의가 한 번 포함되면 컴파일러는 헤더 포함을 충족할 때마다 헤더를 엽니다.
헤더를 여러 번 포함하지 않도록 코드를 편집합니다.
라이브러리의 메인헤더가 아닌 종속헤더의 경우 다음과 같은 헤더 가드를 자주 사용합니다.
#ifdef FOO_BAR_BAZ_H
#error foo_bar_baz.h multiply included
#else
#define FOO_BAR_BAZ_H
// header body
#endif
IIRC, #pragma 어떤 것도 언어의 일부가 아닙니다.그리고 그것은 실제로 많이 나타난다.
(편집:포함 및 링크 시스템은 '오늘의 시대'에서 가장 명백한 약점 중 하나이기 때문에 새로운 표준에 더 중점을 두어야 한다는 데 완전히 동의한다.)
파일에 포함된 클래스 이름과 네임스페이스가 포함되도록 include guard를 설정하면 랜덤 문자열에 의존하지 않고 이름 충돌을 피할 수 있습니다.
게다가 #pragma는 MS 컴파일러와 GCC 양쪽에서 오랫동안 지원되고 있는데, ISO 규격에 맞지 않는 것이 왜 신경이 쓰입니까?
실용적인 솔루션:
1) 일관된 가드 명명 정책을 선택합니다(예: 프로젝트 루트 + 파일 이름 또는 선택한 다른 항목에 상대적인 경로).서드파티제 코드에 대해 가능한 예외를 포함합니다.
2) 소스 트리를 재귀적으로 실행하고 가 모두 정책에 준거하고 있는지 확인하기 위한 프로그램(심플한 python 스크립트)을 작성합니다.또한 가드가 잘못될 때마다 사용자가 쉽게 수정할 수 있는 diff(또는 sed 스크립트 또는 기타)를 출력합니다.또는 확인을 요청하고 같은 프로그램에서 변경하십시오.
3) 프로젝트의 모든 사람이 사용하게 합니다(소스 제어에 제출하기 전 등).
복수의 인크루드(include)를 특수한 플러그마만으로 허가하고, 복수의 인크루드(include)를 디폴트로 허가하지 않는 올바른 방법이라고 생각합니다.예를 들어 다음과 같습니다.
#pragma allow_multiple_include_this_file
이유를 물었으니까.당신의 제안서를 스탠드 아트 개발자들에게 보냈나요?:) 저도 안 보내요.이유가 될 수 있나요?
언급URL : https://stackoverflow.com/questions/1695807/why-isnt-c-cs-pragma-once-an-iso-standard
'programing' 카테고리의 다른 글
jspdf 및 Vue.js를 사용하여 pdf 생성 (0) | 2022.07.14 |
---|---|
vuejs2의 다른 모듈 뮤테이터를 사용하여 모듈 내의 스테이트 프로펠을 변환하는 것이 가능합니까? (0) | 2022.07.14 |
C++는 Java의 인스턴스와 동등합니다. (0) | 2022.07.14 |
Google 글꼴을 VueJS 컴포넌트에 추가하려면 어떻게 해야 하나요? (0) | 2022.07.14 |
prop 인수가 null인 경우 기본값 사용 (0) | 2022.07.14 |