/permissive- (Normenkonformität)

Geben Sie den Standardskonformitätsmodus für den Compiler an. Verwenden Sie diese Option, um Kompatibilitätsprobleme in Ihrem Code zu identifizieren und zu beheben, um es sowohl korrekt als auch portierbarer zu machen.

Syntax

/permissive-
/permissive

Bemerkungen

Die /permissive- Option wird in Visual Studio 2017 und höher unterstützt. /permissive wird in Visual Studio 2019, Version 16.8 und höher, unterstützt.

Sie können die /permissive- Compileroption verwenden, um das Verhalten des standardskonformen Compilers anzugeben. Diese Option deaktiviert zulässige Verhaltensweisen und legt die /Zc Compileroptionen für strenge Übereinstimmung fest. In der IDE wird durch diese Option auch der IntelliSense-Modulcode unterstrichen, der nicht konform ist.

Die /permissive- Option verwendet die Konformitätsunterstützung in der aktuellen Compilerversion, um zu bestimmen, welche Sprachkonstrukte nicht konform sind. Die Option bestimmt nicht, ob Ihr Code einer bestimmten Version des C++-Standards entspricht. Verwenden Sie die /std:c++latest Option, um alle implementierten Compilerunterstützung für den neuesten Entwurfsstandard zu aktivieren. Um die Compilerunterstützung auf den aktuell implementierten C++20-Standard einzuschränken, verwenden Sie die /std:c++20 Option. Um die Compilerunterstützung auf den aktuell implementierten C++17-Standard einzuschränken, verwenden Sie die /std:c++17 Option. Wenn Sie die Compilerunterstützung auf eine genauere Übereinstimmung mit dem C++14-Standard beschränken möchten, verwenden Sie die Option, die /std:c++14 die Standardeinstellung ist.

Die /permissive- Option wird implizit durch die /std:c++latest Option ab Visual Studio 2019, Version 16.8, und in Version 16.11 durch die /std:c++20 Option festgelegt. /permissive- ist für die Unterstützung von C++20-Modulen erforderlich. Möglicherweise benötigt Ihr Code keine Modulunterstützung, erfordert jedoch andere Features, die unter /std:c++20 oder /std:c++latest. Sie können die Microsoft-Erweiterungsunterstützung explizit aktivieren, indem Sie die /permissive Option ohne das nachfolgende Strich verwenden. Die /permissive Option muss nach jeder Option kommen, die implizit festgelegt wird /permissive- .

Standardmäßig wird die Option in neuen Projekten festgelegt, die /permissive- von Visual Studio 2017, Version 15.5 und höher, erstellt wurden. Sie ist in früheren Versionen nicht standardmäßig festgelegt. Wenn die Option festgelegt wird, generiert der Compiler Diagnosefehler oder Warnungen, wenn nicht standardsprachliche Konstrukte im Code erkannt werden. Diese Konstrukte enthalten einige häufige Fehler im Code vor C++11.

Die /permissive- Option ist mit fast allen Headerdateien aus den neuesten Windows Kits kompatibel, z. B. software Development Kit (SDK) oder Windows Driver Kit (WDK), beginnend im Windows Fall Creators SDK (10.0.16299.0). Ältere Versionen des SDK können aus verschiedenen Gründen der Quellcodekonformität möglicherweise nicht kompiliert werden /permissive- . Der Compiler und DIE SDKs werden auf verschiedenen Releasezeitachsen ausgeliefert, daher gibt es einige verbleibende Probleme. Für bestimmte Headerdateiprobleme finden Sie unter Windows-Headerprobleme unten.

Die /permissive- Option legt die Optionen für das /Zc:referenceBinding/Zc:strictStringsverhaltende Verhalten fest/Zc:rvalueCast. Diese Optionen sind standardmäßig für nicht konformes Verhalten verfügbar. Sie können bestimmte /Zc Optionen an /permissive- die Befehlszeile übergeben, um dieses Verhalten außer Kraft zu setzen.

In Versionen des Compilers ab Visual Studio 2017, Version 15.3, legt die /permissive- Option die /Zc:ternary Option fest. Der Compiler implementiert außerdem weitere Anforderungen für die Nachschlagesuche in zwei Phasen. Wenn die /permissive- Option festgelegt wird, analysiert der Compiler Funktions- und Klassenvorlagendefinitionen und identifiziert abhängige und nicht abhängige Namen, die in den Vorlagen verwendet werden. In dieser Version wird nur die Namensabhängigkeitsanalyse ausgeführt.

Umweltspezifische Erweiterungen und Sprachbereiche, die der Standard bis zur Implementierung verlässt, sind nicht betroffen /permissive-. Beispielsweise werden die microsoftspezifischen, aufrufenden __declspecKonventionen und strukturierten Ausnahmebehandlungsstichwörter sowie compilerspezifische pragma Direktiven oder Attribute nicht vom Compiler im /permissive- Modus gekennzeichnet.

Der MSVC-Compiler in früheren Versionen von Visual Studio 2017 unterstützt nicht alle C++11-, C++14- oder C++17-standardskonformen Code. Abhängig von der Version von Visual Studio erkennt die /permissive- Option möglicherweise keine Probleme in einigen Aspekten der zweistufigen Namenssuche, binden Sie einen Nichtkonstverweis auf einen temporären Verweis auf einen temporären, behandeln Kopierinit als direkte Init, sodass mehrere benutzerdefinierte Konvertierungen in initialisierung oder alternative Token für logische Operatoren und andere nicht unterstützte Konformitätsbereiche zulässig sind. Weitere Informationen über Konformitätsprobleme in Visual C++ finden Sie unter Nonstandard Behavior. Um Visual Studio optimal zu /permissive-verwenden, aktualisieren Sie Visual Studio auf die neueste Version.

Beheben des Codes

Nachfolgend finden Sie einige Beispiele für Code, der beim Verwenden /permissive-als nicht konform erkannt wird, zusammen mit den vorgeschlagenen Methoden zum Beheben der Probleme.

Verwenden default als Bezeichner im systemeigenen Code

void func(int default); // Error C2321: 'default' is a keyword, and
                        // cannot be used in this context

Nachschlagen von Mitgliedern in abhängiger Basis

template <typename T>
struct B {
    void f();
};

template <typename T>
struct D : public B<T> // B is a dependent base because its type
                       // depends on the type of T.
{
    // One possible fix is to uncomment the following line.
    // If this is a type, don't forget the 'typename' keyword.
    // using B<T>::f;

    void g() {
        f(); // error C3861: 'f': identifier not found
             // Another fix is to change it to 'this->f();'
    }
};

void h() {
    D<int> d;
    d.g();
}

Verwendung qualifizierter Namen in Memberdeklarationen

struct A {
    void A::f() { } // error C4596: illegal qualified name in member
                    // declaration.
                    // Remove redundant 'A::' to fix.
};

Initialisieren mehrerer Unionmitglieder in einem Mitgliedsinitializer

union U
{
    U()
        : i(1), j(1) // error C3442: Initializing multiple members of
                     // union: 'U::i' and 'U::j'.
                     // Remove all but one of the initializations to fix.
    {}
    int i;
    int j;
};

Nachschlageregeln für ausgeblendete Freunde

Eine Deklaration außerhalb einer Klasse kann einen ausgeblendeten Freund sichtbar machen:

// Example 1
struct S {
    friend void f(S *);
};
// Uncomment this declaration to make the hidden friend visible:
// void f(S *); // This declaration makes the hidden friend visible

using type = void (*)(S *);
type p = &f; // error C2065: 'f': undeclared identifier.

Die Verwendung von Literal nullptr kann die abhängige Nachschlagevorgänge von Argumenten verhindern:

// Example 2
struct S {
    friend void f(S *);
};
void g() {
    // Using nullptr instead of S prevents argument dependent lookup in S
    f(nullptr); // error C3861: 'f': identifier not found

    S *p = nullptr;
    f(p); // Hidden friend now found via argument-dependent lookup.
}

Sie können die Nachschlageregeln für ausgeblendete Freunde unabhängig von /permissive der Verwendung aktivieren /Zc:hiddenFriend. Wenn Sie das Legacyverhalten für die Suche nach ausgeblendeten Freundnamen wünschen, andernfalls jedoch verhalten möchten /permissive- , verwenden Sie die /Zc:hiddenFriend- Option.

Verwenden von Bereichsenumen in Arraygrenzen

enum class Color {
    Red, Green, Blue
};

int data[Color::Blue]; // error C3411: 'Color' is not valid as the size
                       // of an array as it is not an integer type.
                       // Cast to type size_t or int to fix.

Verwenden für jeden in systemeigenem Code

void func() {
    int array[] = {1, 2, 30, 40};
    for each (int i in array) // error C4496: nonstandard extension
                              // 'for each' used: replace with
                              // ranged-for statement:
                              // for (int i: array)
    {
        // ...
    }
}

Verwendung von ATL-Attributen

Microsoft-spezifische ATL-Attribute können Probleme unter /permissive-:

// Example 1
[uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")]
class A {};

Sie können das Problem mithilfe des __declspec Formulars beheben:

// Fix for example 1
class __declspec(uuid("594382D9-44B0-461A-8DE3-E06A3E73C5EB")) B {};

Ein komplexeres Beispiel:

// Example 2
[emitidl];
[module(name="Foo")];

[object, local, uuid("9e66a290-4365-11d2-a997-00c04fa37ddb")]
__interface ICustom {
    HRESULT Custom([in] longl, [out, retval] long*pLong);
    [local] HRESULT CustomLocal([in] longl, [out, retval] long*pLong);
};

[coclass, appobject, uuid("9e66a294-4365-11d2-a997-00c04fa37ddb")]
class CFoo : public ICustom
{};

Die Auflösung erfordert zusätzliche Buildschritte. Erstellen Sie in diesem Fall eine IDL-Datei:

// Fix for example 2
// First, create the *.idl file. The vc140.idl generated file can be
// used to automatically obtain a *.idl file for the interfaces with
// annotation. Second, add a midl step to your build system to make
// sure that the C++ interface definitions are outputted.
// Last, adjust your existing code to use ATL directly as shown in
// the atl implementation section.

-- IDL  FILE--
import "docobj.idl";

[object, local, uuid(9e66a290-4365-11d2-a997-00c04fa37ddb)]
interface ICustom : IUnknown {
    HRESULT Custom([in] longl, [out,retval] long*pLong);
    [local] HRESULT CustomLocal([in] longl, [out,retval] long*pLong);
};

[ version(1.0), uuid(29079a2c-5f3f-3325-99a1-3ec9c40988bb) ]
library Foo {
    importlib("stdole2.tlb");
    importlib("olepro32.dll");

    [version(1.0), appobject, uuid(9e66a294-4365-11d2-a997-00c04fa37ddb)]
    coclass CFoo { interface ICustom; };
}

-- ATL IMPLEMENTATION--
#include <idl.header.h>
#include <atlbase.h>

class ATL_NO_VTABLE CFooImpl : public ICustom,
    public ATL::CComObjectRootEx<CComMultiThreadModel>
{
    public:BEGIN_COM_MAP(CFooImpl)
    COM_INTERFACE_ENTRY(ICustom)
    END_COM_MAP()
};

Mehrdeutige Argumente für bedingte Operatoren

In Versionen des Compilers vor Visual Studio 2017, Version 15.3, akzeptierte der Compiler Argumente an den bedingten Operator (oder den ternären Operator), ?: die vom Standard als mehrdeutig betrachtet werden. Im /permissive- Modus stellt der Compiler jetzt eine oder mehrere Diagnosen in Fällen aus, die ohne Diagnose in früheren Versionen kompiliert wurden.

Häufige Fehler, die zu dieser Änderung führen können, sind:

  • error C2593: 'operator ?' is ambiguous

  • error C2679: binary '?': no operator found which takes a right-hand operand of type 'B' (or there is no acceptable conversion)

  • error C2678: binary '?': no operator found which takes a left-hand operand of type 'A' (or there is no acceptable conversion)

  • error C2446: ':': no conversion from 'B' to 'A'

Ein typisches Codemuster, das dieses Problem verursachen kann, besteht darin, dass einige Klassen C einen nicht expliziten Konstruktor von einem anderen Typ T und einem nicht expliziten Konvertierungsoperator zum Typ Tbereitstellt. Die Konvertierung des zweiten Arguments in den Typ des dritten Arguments ist eine gültige Konvertierung. Dies ist die Konvertierung des dritten Arguments in den Typ des zweiten Arguments. Da beide gültig sind, ist es nach dem Standard mehrdeutig.

// Example 1: class that provides conversion to and initialization from some type T
struct A
{
    A(int);
    operator int() const;
};

extern bool cond;

A a(42);
// Accepted when /Zc:ternary or /permissive- is not used:
auto x = cond ? 7 : a; // A: permissive behavior prefers A(7) over (int)a
// Accepted always:
auto y = cond ? 7 : int(a);
auto z = cond ? A(7) : a;

Es gibt eine wichtige Ausnahme für dieses allgemeine Muster, wenn T einen der null-beendeten Zeichenfolgentypen (z. B const char *. , const char16_t *usw.) darstellt und das tatsächliche Argument ?: ein Zeichenfolgenliteral des entsprechenden Typs ist. C++17 hat die Semantik von C++14 geändert. Daher wird der Code in Beispiel 2 unter /std:c++14 oder höher akzeptiert und abgelehnt /std:c++17 , wenn /Zc:ternary oder /permissive- später verwendet wird.

// Example 2: exception from the above
struct MyString
{
    MyString(const char* s = "") noexcept;  // from char*
    operator const char* () const noexcept; //   to char*
};

extern bool cond;

MyString s;
// Using /std:c++14, /permissive- or /Zc:ternary behavior
// is to prefer MyString("A") over (const char*)s
// but under /std:c++17 this line causes error C2445:
auto x = cond ? "A" : s;
// You can use a static_cast to resolve the ambiguity:
auto y = cond ? "A" : static_cast<const char*>(s);

Möglicherweise werden auch Fehler in bedingten Operatoren mit einem Argument vom Typ voidangezeigt. Dieser Fall kann in ASSERTION-ähnlichen Makros üblich sein.

// Example 3: void arguments
void myassert(const char* text, const char* file, int line);
// Accepted when /Zc:ternary or /permissive- is not used:
#define ASSERT_A(ex) (void)((ex) ? 1 : myassert(#ex, __FILE__, __LINE__))
// Accepted always:
#define ASSERT_B(ex) (void)((ex) ? void() : myassert(#ex, __FILE__, __LINE__))

Möglicherweise werden auch Fehler in der Vorlagenmetaprogrammierung angezeigt, bei denen die Ergebnistypen /Zc:ternary des bedingten Operators unter und ./permissive- Eine Möglichkeit zum Beheben dieses Problems besteht darin, den resultierenden Typ zu verwenden std::remove_reference .

// Example 4: different result types
extern bool cond;
extern int count;
char  a = 'A';
const char  b = 'B';
decltype(auto) x = cond ? a : b; // char without, const char& with /Zc:ternary
const char (&z)[2] = count > 3 ? "A" : "B"; // const char* without /Zc:ternary

Nachschlagename in zwei Phasen

Wenn die /permissive- Option festgelegt wird, analysiert der Compiler Funktions- und Klassenvorlagendefinitionen, identifiziert abhängige und nicht abhängige Namen, die in Vorlagen als erforderlich für die Nachschlagefunktion von zwei Phasen verwendet werden. In Visual Studio 2017, Version 15.3, wird die Namensabhängigkeitsanalyse ausgeführt. Insbesondere nicht abhängige Namen, die nicht im Kontext einer Vorlagendefinition deklariert werden, führen zu einer Diagnosemeldung, die von den ISO C++-Standards benötigt wird. In Visual Studio 2017, Version 15.7, erfolgt auch die Bindung nicht abhängiger Namen, die argumentabhängige Suche im Definitionskontext erfordern.

// dependent base
struct B {
    void g() {}
};

template<typename T>
struct D : T {
    void f() {
        // The call to g was incorrectly allowed in VS2017:
        g();  // Now under /permissive-: C3861
        // Possible fixes:
        // this->g();
        // T::g();
    }
};

int main()
{
    D<B> d;
    d.f();
}

Wenn Sie das Legacyverhalten für die zweistufige Suche benötigen, andernfalls jedoch verhalten möchten /permissive- , fügen Sie die /Zc:twoPhase- Option hinzu.

Windows-Headerprobleme

Die /permissive- Option ist für Versionen von Windows Kits zu streng, bevor Windows Fall Creators Update SDK (10.0.16299.0) oder windows Driver Kit (WDK) Version 1709. Es wird empfohlen, auf die neuesten Versionen der Windows Kits zu aktualisieren, die in Ihrem Windows- oder Gerätetreibercode verwendet werden /permissive- sollen.

Bestimmte Headerdateien im Windows April 2018 Update SDK (10.0.17134.0), das Windows Fall Creators Update SDK (10.0.16299.0) oder das Windows Driver Kit (WDK) 1709 verfügen weiterhin über Probleme, die sie mit der Verwendung /permissive-nicht kompatibel machen. Um diese Probleme zu umgehen, sollten Sie die Verwendung dieser Header nur auf diese Quellcodedateien beschränken, die sie benötigen, und die /permissive- Option entfernen, wenn Sie diese spezifischen Quellcodedateien kompilieren.

Diese WinRT WRL-Header, die im Windows April 2018 Update SDK (10.0.17134.0) veröffentlicht wurden, sind nicht sauber mit /permissive-. Um diese Probleme zu umgehen, verwenden Sie entweder nicht, oder verwenden /permissive-/permissive-/Zc:twoPhase- Sie sie, wenn Sie mit diesen Headern arbeiten:

  • Probleme in winrt/wrl/async.h

    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(483): error C3861: 'TraceDelegateAssigned': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(491): error C3861: 'CheckValidStateForDelegateCall': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(509): error C3861: 'TraceProgressNotificationStart': identifier not found
    C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\wrl\async.h(513): error C3861: 'TraceProgressNotificationComplete': identifier not found
    
  • Problem in winrt/wrl/implements.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\winrt\wrl\implements.h(2086): error C2039: 'SetStrongReference': is not a member of 'Microsoft::WRL::Details::WeakReferenceImpl'
    

Diese im Windows April 2018 Update SDK (10.0.17134.0) veröffentlichten Benutzermodusheader sind nicht sauber mit /permissive-. Um diese Probleme zu umgehen, verwenden /permissive- Sie beim Arbeiten mit diesen Headern nicht:

  • Probleme in um/Tune.h

    C:\ProgramFiles(x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(139): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(559): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(1240): error C3861: 'Release': identifier not found
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\tune.h(1240): note: 'Release': function declaration must be available as none of the arguments depend on a template parameter
    
  • Problem in um/spddkhlp.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\spddkhlp.h(759): error C3861: 'pNode': identifier not found
    
  • Probleme in um/refptrco.h

    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(179): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(342): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um\refptrco.h(395): error C2760: syntax error: unexpected token 'identifier', expected 'type specifier'
    

Diese Probleme sind spezifisch für Benutzermodusheader im Windows Fall Creators Update SDK (10.0.16299.0):

  • Problem in um/Query.h

    Wenn Sie den Compilerschalter verwenden, wird die tagRESTRICTION Struktur aufgrund des /permissive-case(RTOr) Members ornicht kompiliert.

    struct tagRESTRICTION
    {
         ULONG rt;
         ULONG weight;
         /* [switch_is][switch_type] */ union _URes
         {
             /* [case()] */ NODERESTRICTION ar;
             /* [case()] */ NODERESTRICTION or;  // error C2059: syntax error: '||'
             /* [case()] */ NODERESTRICTION pxr;
             /* [case()] */ VECTORRESTRICTION vr;
             /* [case()] */ NOTRESTRICTION nr;
             /* [case()] */ CONTENTRESTRICTION cr;
             /* [case()] */ NATLANGUAGERESTRICTION nlr;
             /* [case()] */ PROPERTYRESTRICTION pr;
             /* [default] */  /* Empty union arm */
         } res;
    };
    

    Um dieses Problem zu beheben, kompilieren Sie Dateien, die ohne die /permissive- Option enthalten sindQuery.h.

  • Problem in um/cellularapi_oem.h

    Wenn Sie den Compilerschalter verwenden, führt die /permissive- Weiterleitungsdeklaration enum UICCDATASTOREACCESSMODE zu einer Warnung:

    typedef enum UICCDATASTOREACCESSMODE UICCDATASTOREACCESSMODE; // C4471
    

    Die Weiterleitungsdeklaration einer unscoped enum ist eine Microsoft-Erweiterung. Um dieses Problem zu beheben, kompilieren Sie Dateien, die ohne /permissive- die Option enthalten cellularapi_oem.h sind, oder verwenden Sie die /wd Option zum Stillen der Warnung C4471.

  • Problem in um/omscript.h

    In C++03 ist eine Konvertierung von einer Zeichenfolge literal BSTR zu (was ein Typdef in wchar_t *) ist veraltet, aber zulässig. In C++11 ist die Konvertierung nicht mehr zulässig.

    virtual /* [id] */ HRESULT STDMETHODCALLTYPE setExpression(
         /* [in] */ __RPC__in BSTR propname,
         /* [in] */ __RPC__in BSTR expression,
         /* [in][defaultvalue] */ __RPC__in BSTR language = L"") = 0; // C2440
    

    Um dieses Problem zu beheben, kompilieren Sie Dateien, die omscript.h ohne Option /permissive- enthalten oder stattdessen verwenden /Zc:strictStrings- .

So legen Sie diese Compileroption in der Visual Studio-Entwicklungsumgebung fest

Verwenden Sie in Visual Studio 2017 Version 15.5 und höher diese Prozedur:

  1. Öffnen Sie das Dialogfeld "Eigenschaftenseiten " ihres Projekts.

  2. Wählen Sie die Seite "Konfigurationseigenschaften>C/C++>Language" aus.

  3. Ändern Sie den Eigenschaftswert " Conformance Mode " in "Ja" (/permissive-). Wählen Sie "OK " oder " Anwenden " aus, um Ihre Änderungen zu speichern.

Verwenden Sie in Versionen vor Visual Studio 2017 Version 15.5 folgendes Verfahren:

  1. Öffnen Sie das Dialogfeld "Eigenschaftenseiten " ihres Projekts.

  2. Wählen Sie die Eigenschaftsseite "Konfigurationseigenschaften>C/C++>" aus.

  3. Geben Sie die Option "/permissive- compiler" im Feld "Zusätzliche Optionen " ein. Wählen Sie "OK " oder " Anwenden " aus, um Ihre Änderungen zu speichern.

So legen Sie diese Compileroption programmgesteuert fest

Siehe auch

MSVC-Compileroptionen
Syntax für die MSVC-Compilerbefehlszeile