programing

C/C++의 "#pragma once"가 ISO 표준이 아닌 이유는 무엇입니까?

randomtip 2022. 7. 14. 21:22
반응형

C/C++의 "#pragma once"가 ISO 표준이 아닌 이유는 무엇입니까?

저는 지금 큰 프로젝트를 하고 있는데, 경비원을 포함한 모든 것을 유지하는 것이 저를 미치게 해요!손으로 쓰는 것은 답답한 시간 낭비입니다.많은 편집자가 가드 포함을 생성할 수 있지만 이는 큰 도움이 되지 않습니다.

  1. Editor는 파일 이름을 기반으로 가드 기호를 생성합니다.이 문제는, 같은 파일명을 가지는 헤더가 다른 디렉토리에 있는 경우에 발생합니다.둘 다 가드를 포함해서 같은 점수를 받을 것이다.디렉토리 구조를 guard 심볼에 포함시키는 것은 매크로의 슬래시와 백슬래시는 최선이 아니기 때문에 에디터의 세련된 접근법이 필요합니다.

  2. 파일 이름을 변경해야 할 경우 모든 포함 가드 이름도 변경해야 합니다(ifndef에서 endif 주석 정의 및 이상적).짜증나는.

  3. 프리프로세서는 수많은 기호들로 가득 차서 무슨 뜻인지 알 수 없다.

  4. 그럼에도 불구하고 정의가 한 번 포함되면 컴파일러는 헤더 포함을 충족할 때마다 헤더를 엽니다.

  5. 네임스페이스나 템플릿에는 가드를 사용할 수 없습니다.사실 그들은 네임스페이스를 파괴하고 있어요!

  6. 당신의 가드 기호가 독특하지 않을 가능성이 있습니다.

프로그램이 단일 디렉토리에 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에 포함할 이유가 전혀 없습니다.하지만 난 알아 - 내 생각에, 전통.

  1. 이 프로젝트에 포함 파일을 얼마나 자주 추가해야 합니까?가드에 DIRNAME_FILNAME을 추가하는 것이 그렇게 어려운가요?그리고 항상 GUID가 있습니다.
  2. 정말 그렇게 자주 파일 이름을 바꾸나요?가드를 #endif에 넣는 것은 다른 쓸데없는 댓글과 마찬가지로 짜증난다.
  3. 1000 헤더 파일 가드 정의가 시스템 라이브러리(특히 Windows)에 의해 생성되는 정의 수보다 적은 비율인지 의심됩니다.
  4. MSC 10 for DOS(20년 이상 전)는 어떤 헤더가 포함되어 있는지, 또 포함되었을 경우 가드가 포함되어 있는지 추적하고 있었다고 생각합니다.이건 오래된 기술이야
  5. 네임스페이스와 템플릿은 헤더를 확장하지 않아야 합니다.설마 이런 짓을 하는 건 아니겠지?

    template <typename foo>
    class bar {
    #include "bar_impl.h"
    };
    
  6. 이미 말했잖아요.

이미 기술한 바와 같이 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

반응형