답에는 두 부분이 있습니다. 컴파일러 수준에서의 호환성 및 링커 수준에서의 호환성. 전자부터 시작합시다.
모든 헤더가 C ++ 11로 작성되었다고 가정 해 보겠습니다.
동일한 컴파일러를 사용한다는 것은 타겟 C ++ 표준에 관계없이 동일한 표준 라이브러리 헤더 및 소스 파일 (컴파일러와 관련된 파일)이 사용된다는 것을 의미합니다. 따라서 표준 라이브러리의 헤더 파일은 컴파일러에서 지원하는 모든 C ++ 버전과 호환되도록 작성됩니다.
즉, 번역 단위를 컴파일하는 데 사용되는 컴파일러 옵션이 특정 C ++ 표준을 지정하는 경우 최신 표준에서만 사용할 수있는 모든 기능에 액세스 할 수 없습니다. 이것은 __cplusplus
지시문을 사용하여 수행됩니다 . 사용 방법에 대한 흥미로운 예 는 벡터 소스 파일을 참조하십시오 . 마찬가지로 컴파일러는 최신 버전의 표준에서 제공하는 모든 구문 기능을 거부합니다.
그 모든 것은 당신의 가정이 당신이 작성한 헤더 파일에만 적용될 수 있음을 의미합니다. 이러한 헤더 파일은 다른 C ++ 표준을 대상으로하는 다른 번역 단위에 포함될 때 비 호환성을 유발할 수 있습니다. 이것은 C ++ 표준의 부록 C에서 논의됩니다. 4 개의 절이 있습니다. 첫 번째 절만 논의하고 나머지는 간단히 언급하겠습니다.
C.3.1 조항 2 : 어휘 규약
작은 따옴표는 C ++ 11에서 문자 리터럴을 구분하는 반면 C ++ 14 및 C ++ 17에서는 숫자 구분 기호입니다. 순수 C ++ 11 헤더 파일 중 하나에 다음 매크로 정의가 있다고 가정합니다.
#define M(x, ...) __VA_ARGS__
int x[2] = { M(1'2,3'4) };
헤더 파일을 포함하지만 각각 C ++ 11 및 C ++ 14를 대상으로하는 두 개의 변환 단위를 고려하십시오. C ++ 11을 대상으로 할 때 따옴표 안의 쉼표는 매개 변수 구분 기호로 간주되지 않습니다. 매개 변수는 한 번만 있습니다. 따라서 코드는 다음과 같습니다.
int x[2] = { 0 };
반면에 C ++ 14를 대상으로 할 때 작은 따옴표는 숫자 구분 기호로 해석됩니다. 따라서 코드는 다음과 같습니다.
int x[2] = { 34, 0 };
여기서 중요한 점은 순수한 C ++ 11 헤더 파일 중 하나에 작은 따옴표를 사용하면 C ++ 14 / 17을 대상으로하는 번역 단위에서 놀라운 버그가 발생할 수 있다는 것입니다. 따라서 헤더 파일이 C ++ 11로 작성된 경우에도 이후 버전의 표준과 호환되도록 신중하게 작성해야합니다. 여기서 __cplusplus
지시문이 유용 할 수 있습니다.
표준의 다른 세 가지 조항은 다음과 같습니다.
C.3.2 Clause 3 : 기본 개념
변경 : 새로운 보통 (비 배치) 할당 해제
근거 : 크기가 지정된 할당 해제에 필요합니다.
원래 기능에 대한 영향 : 유효한 C ++ 2011 코드는 다음과 같이 전역 배치 할당 함수 및 할당 해제 함수를 선언 할 수 있습니다.
void operator new(std::size_t, std::size_t);
void operator delete(void*, std::size_t) noexcept;
그러나이 국제 표준에서 연산자 삭제 선언은 사전 정의 된 일반 (비 배치) 연산자 삭제 (3.7.4)와 일치 할 수 있습니다. 만약 그렇다면, 프로그램은 클래스 멤버 할당 함수와 할당 해제 함수 (5.3.4)와 같이 잘못된 형식입니다.
C.3.3 Clause 7 : 선언
변경 사항 : constexpr 비 정적 멤버 함수는 암시 적으로 const 멤버 함수가 아닙니다.
근거 : constexpr 멤버 함수가 개체를 변경하도록 허용하는 데 필요합니다.
원래 기능에 대한 영향 : 유효한 C ++ 2011 코드가이 국제 표준에서 컴파일되지 않을 수 있습니다.
예를 들어, 다음 코드는 C ++ 2011에서 유효하지만 다른 반환 유형으로 동일한 멤버 함수를 두 번 선언하므로이 국제 표준에서는 유효하지 않습니다.
struct S {
constexpr const int &f();
int &f();
};
C.3.4 Clause 27 : 입력 / 출력 라이브러리
변경 : 가져 오기가 정의되지 않았습니다.
근거 : get의 사용은 위험한 것으로 간주됩니다.
원래 기능에 미치는 영향 :이 국제 표준에서는 gets 함수를 사용하는 유효한 C ++ 2011 코드가 컴파일되지 않을 수 있습니다.
C ++ 14와 C ++ 17 간의 잠재적 인 비 호환성에 대해서는 C.4에서 설명합니다. 모든 비표준 헤더 파일은 C ++ 11 (질문에 명시된대로)로 작성되었으므로 이러한 문제는 발생하지 않으므로 여기서 언급하지 않겠습니다.
이제 링커 수준에서 호환성에 대해 설명하겠습니다. 일반적으로 비 호환성에 대한 잠재적 인 이유는 다음과 같습니다.
- 개체 파일의 형식입니다.
- 프로그램 시작 및 종료 루틴과
main
진입 점.
- 전체 프로그램 최적화 (WPO).
결과 개체 파일의 형식이 대상 C ++ 표준에 따라 달라지는 경우 링커는 다른 개체 파일을 연결할 수 있어야합니다. GCC, LLVM 및 VC ++에서는 다행히도 그렇지 않습니다. 즉, 객체 파일의 형식은 컴파일러 자체에 크게 의존하지만 대상 표준에 관계없이 동일합니다. 실제로 GCC, LLVM 및 VC ++의 링커는 대상 C ++ 표준에 대한 지식이 필요하지 않습니다. 이것은 또한 이미 컴파일 된 객체 파일을 링크 할 수 있음을 의미합니다 (런타임을 정적으로 링크).
프로그램 시작 루틴 (을 호출하는 함수 main
)이 다른 C ++ 표준에 대해 다르고 다른 루틴이 서로 호환되지 않는 경우 개체 파일을 연결할 수 없습니다. GCC, LLVM 및 VC ++에서는 다행히도 그렇지 않습니다. 또한 main
함수 의 서명 (및 이에 적용되는 제한 사항, 표준의 섹션 3.6 참조)은 모든 C ++ 표준에서 동일하므로 어떤 번역 단위에 존재하는지는 중요하지 않습니다.
일반적으로 WPO는 다른 C ++ 표준을 사용하여 컴파일 된 개체 파일에서 제대로 작동하지 않을 수 있습니다. 이것은 정확히 어떤 단계의 컴파일러가 대상 표준에 대한 지식을 필요로하고 어떤 단계가 필요하지 않은지, 객체 파일을 교차하는 절차 간 최적화에 미치는 영향에 따라 다릅니다. 다행히 GCC, LLVM 및 VC ++는 잘 설계되어 있으며이 문제가 없습니다 (내가 알지 못함).
따라서 GCC, LLVM 및 VC ++는 여러 버전의 C ++ 표준에서 이진 호환성 을 지원하도록 설계되었습니다 . 이것은 실제로 표준 자체의 요구 사항은 아닙니다.
그런데 VC ++ 컴파일러는 특정 버전의 C ++ 표준을 대상으로 할 수 있는 std 스위치를 제공하지만 C ++ 11 대상 지정을 지원하지 않습니다. 지정할 수있는 최소 버전은 Visual C ++ 2013 업데이트 3부터 시작되는 기본값 인 C ++ 14입니다. 이전 버전의 VC ++를 사용하여 C ++ 11을 대상으로 할 수 있지만 다른 VC ++ 컴파일러를 사용해야합니다. C ++ 표준의 서로 다른 버전을 대상으로하는 서로 다른 번역 단위를 컴파일하기 위해 최소한 WPO가 중단됩니다.
주의 : 내 대답은 완전하지 않거나 매우 정확하지 않을 수 있습니다.