Freigeben über


Empfohlene Vorgehensweisen und Beispiele (SAL)

Es gibt folgende Möglichkeiten, die die meisten aus Annotation Language (SAL) abzurufen und einige allgemeine Probleme zu vermeiden.

_In_

Wenn die Funktion zum Element schreiben soll, verwenden Sie _Inout_ anstelle _In_.Dies ist bei automatisierten Konvertierung von älteren Makros zum SAL besonders relevant.Vor SAL haben viele Programmierer Makros als KommentarMakros, die IN, OUT, IN_OUT oder Varianten dieser Namen benannt wurden.Obwohl empfohlen, dass Sie diese Makros zum SAL konvertieren, wir auch UMSCHALT+ALT+X drücken Sie auch, achtzugeben, wenn Sie sie konvertieren, da der Code möglicherweise geändert, seit der ursprüngliche Prototyp geschrieben wurde und das alte Makro möglicherweise nicht mehr reflektierte, welchem Zweck.Geben Sie insbesondere zum OPTIONAL Kommentarmakro, da oftmals falsch-für Beispiel platziert wird, für die falsche Seite eines Kommas acht.

// Incorrect
void Func1(_In_ int *p1)
{
    if (p1 == NULL) 
        return;

    *p1 = 1;
}

// Correct
void Func2(_Inout_ PCHAR p1)
{
    if (p1 == NULL) 
        return;

    *p1 = 1;
}

_opt_

Wenn der Aufrufer nicht übergeben Sie in einem NULL-Zeiger zulässig ist, verwenden Sie _In_ oder _Out_ anstelle _In_opt_ oder _Out_opt_.Dies gilt sogar auf eine Funktion auf, die die Parameter überprüft und einen Fehler zurückgibt, wenn er NULL ist, wenn es nicht sein sollte.Obwohl, eine Funktionsüberprüfung resultieren, dessen - Parameter für unerwartete NULL und Rückgabe ordnungsgemäß gutes defensives Codierungsüblich ist, bedeutet dies nicht, dass die Parameteranmerkung aus einem optionalen Typ (_Xxx_opt_) sein kann.

// Incorrect
void Func1(_Out_opt_ int *p1)
{
    *p = 1;
}

// Correct
void Func2(_Out_ int *p1)
{
    *p = 1;
}

_Pre_defensive_ und _Post_defensive_

Wenn eine Funktion an einer Vertrauenswürdigkeitsgrenze angezeigt wird, wird empfohlen, die _Pre_defensive_ Anmerkung verwenden.Der "defensive" Modifizierer ändert bestimmte Anmerkungen, um anzugeben, dass, zum Zeitpunkt des Aufrufs, die Schnittstelle sollte ausschließlich überprüft werden übergeben würden, aber im Implementierungstext sie annehmen soll, dass möglicherweise falsche Parameter.In diesem Fall wird _In_ _Pre_defensive_ an einer Vertrauenswürdigkeitsgrenze bevorzugt, um anzugeben, dass, obwohl ein Aufrufer einen Fehler abruft, wenn er versucht, NULL zu übergeben, der Funktionsrumpf, als ob der Parameter möglicherweise NULL ist, und alle Versuche, den Zeiger ohne erste Überprüfung zu dereferenzieren analysiert wird, für die er NULL bezeichnet wird.Eine _Post_defensive_ Anmerkung ebenfalls, für die Rückrufe verfügbar, in denen die vertrauenswürdige Seite angenommen wird, dass der Aufrufer sein und der nicht vertrauenswürdigen Code der aufgerufenen Code ist.

_Out_writes_

Im folgenden Beispiel wird eine häufige Verwendung von _Out_writes_.

// Incorrect
void Func1(_Out_writes_(size) CHAR *pb, 
    DWORD size
);

Die Anmerkung _Out_writes_ gibt an, dass Sie einen Puffer haben.Sie können cb Bytes zuordnen, wenn das erste Byte auf Beendigung initialisiert ist.Diese Anmerkung ist nicht unbedingt falsch und ist es hilfreich, die zugeordnete Größe auszudrücken.Allerdings wird nicht mit, wie viele Elemente durch die Funktion initialisiert werden.

Im nächsten Beispiel wird richtige drei Möglichkeiten, die genaue Größe des initialisierten Teils des Puffers vollständig anzugeben.

// Correct
void Func1(_Out_writes_to_(size, *pCount) CHAR *pb, 
    DWORD size,
    PDWORD pCount
);

void Func2(_Out_writes_all_(size) CHAR *pb, 
    DWORD size
);

void Func3(_Out_writes_(size) PSTR pb, 
    DWORD size
);

_Out_ PSTR

Die Verwendung von _Out_ PSTR ist fast immer ungültig.Dies wird als interpretiert, einen Ausgabeparameter aufweisen, der zeigt auf einen Zeichenpuffer und Daten auf NULL endende ist.

// Incorrect
void Func1(_Out_ PSTR pFileName, size_t n);

// Correct
void Func2(_Out_writes_(n) PSTR wszFileName, size_t n);

Eine Anmerkung wie _In_ PCSTR ist häufig und hilfreich.Sie zeigt auf eine Eingabezeichenfolge, die NULL beendet hat, da die Vorbedingung der _In_ die Erkennung einer auf NULL endende Zeichenfolge zulässig.

_In_ WCHAR* p

_In_ WCHAR* p besagt, dass ein Eingabezeiger p gibt, der einem Zeichen zeigt.In den meisten Fällen ist dies wahrscheinlich nicht die Spezifikation, die vorgesehen.Stattdessen was wahrscheinlich vorgesehen ist, ist die Angabe eines auf NULL endende Arrays; um das auszuführen, verwenden Sie _In_ PWSTR.

// Incorrect
void Func1(_In_ WCHAR* wszFileName);

// Correct
void Func2(_In_ PWSTR wszFileName);

Die richtige Spezifikation der NULL Ende von fehlen ist häufig.Verwenden Sie die entsprechende STR-Version, um den Typ, wie im folgenden Beispiel gezeigt zu ersetzen.

// Incorrect
BOOL StrEquals1(_In_ PCHAR p1, _In_ PCHAR p2)
{
    return strcmp(p1, p2) == 0;
}

// Correct
BOOL StrEquals2(_In_ PSTR p1, _In_ PSTR p2)
{
    return strcmp(p1, p2) == 0;
}

_Out_range_

Wenn der - Parameter ein Zeiger ist und Sie den Bereich den Wert des Elements wiedergeben möchten, das von dem Zeiger verweist, verwenden Sie _Deref_out_range_ anstelle _Out_range_.Im folgenden Beispiel wird der Bereich von *pcbFilled ausgedrückt, pcbFilled nicht.

// Incorrect
void Func1(
    _Out_writes_bytes_to_(cbSize, *pcbFilled) BYTE *pb, 
    DWORD cbSize, 
    _Out_range_(0, cbSize) DWORD *pcbFilled
);

// Correct
void Func2(
    _Out_writes_bytes_to_(cbSize, *pcbFilled) BYTE *pb, 
    DWORD cbSize, 
    _Deref_out_range_(0, cbSize) _Out_ DWORD *pcbFilled 
);

_Deref_out_range_(0, cbSize) ist nicht zwingend für mehrere Tools erforderlich, da es von _Out_writes_to_(cbSize,*pcbFilled) abgeleitet werden kann, wird hier jedoch auf Vollständigkeit angezeigt.

Falscher Kontext im _When_

Ein weiterer häufiger Fehler ist, Nach-Zustandsauswertung für Vorbedingungen zu verwenden.Im folgenden Beispiel ist _Requires_lock_held_ eine Vorbedingung.

// Incorrect
_When_(return == 0, _Requires_lock_held_(p->cs))
int Func1(_In_ MyData *p, int flag);

// Correct
_When_(flag == 0, _Requires_lock_held_(p->cs))
int Func2(_In_ MyData *p, int flag);

Der Ausdruck result verweist auf einen Nach-Zustandswert an, der nicht im Vor-Zustand verfügbar ist.

TRUE im _Success_

Wenn die Funktion erfolgreich ist, wenn der Rückgabewert ungleich 0 (null) ist, verwenden Sie return != 0 als die Erfolgszustand anstelle return == TRUE.Wert ungleich 0 bedeutet nicht notwendigerweise Äquivalenz auf den tatsächlichen Wert, den der Compiler für TRUE bereitstellt.Der Parameter zu _Success_ ist ein Ausdruck, und die folgenden Ausdrücke werden als äquivalent ausgewertet: return != 0, return != false, return != FALSE und return ohne Parameter oder Vergleiche.

// Incorrect
_Success_(return == TRUE, _Acquires_lock_(*lpCriticalSection))
BOOL WINAPI TryEnterCriticalSection(
  _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

// Correct
_Success_(return != 0, _Acquires_lock_(*lpCriticalSection))
BOOL WINAPI TryEnterCriticalSection(
  _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

Verweisvariable

Für eine Verweisvariable verwendet die frühere Version des SALZES den impliziten Zeiger als das Anmerkungsziel und erfordert die Addition von __deref zu den Anmerkungen, die einer - Verweisvariable angefügt wurde.Diese Version verwendet das Objekt selbst und erfordert keine zusätzliche _Deref_.

// Incorrect
void Func1(
    _Out_writes_bytes_all_(cbSize) BYTE *pb, 
    _Deref_ _Out_range_(0, 2) _Out_ DWORD &cbSize
);

// Correct
void Func2(
    _Out_writes_bytes_all_(cbSize) BYTE *pb, 
    _Out_range_(0, 2) _Out_ DWORD &cbSize
);

Anmerkungen auf Rückgabewerten

Im folgenden Beispiel wird ein häufiges Problem bewerten als Minderung Anmerkungen an.

// Incorrect
_Out_opt_ void *MightReturnNullPtr1();

// Correct
_Ret_maybenull_ void *MightReturnNullPtr2();

In diesem Beispiel _Out_opt_ besagt, dass der Zeiger möglicherweise als Teil der Vorbedingung NULL sein kann.Allerdings können Vorbedingungen nicht auf den Rückgabewert angewendet werden.In diesem Fall ist die richtige Anmerkung _Ret_maybenull_.

Siehe auch

Referenz

Hinzufügen einer Anmerkung zu Funktionsparametern und Rückgabewerten

Hinzufügen einer Anmerkung zum Funktionsverhalten

Hinzufügen einer Anmerkung zu Strukturen und Klassen

Hinzufügen einer Anmerkung zum Sperrverhalten

Angeben, wann und wo eine Anmerkung gültig ist

Systeminterne Funktionen

Konzepte

Einführung in SAL

Weitere Ressourcen

Verwenden von SAL-Anmerkungen zum Reduzieren von C/C++-Codefehlern