_In_
und _Out_
(Hinweis: Weder _in_/_out
_ wie Sie geschrieben haben, noch __In__/__Out__
mit doppelten Unterstrichen, wie in einigen anderen Antworten geschrieben) sind sogenannte SAL-Annotationen. Sie können mit der /analyze
-Compileroption verwendet werden und können dabei helfen, Fehler und Probleme wie Pufferüberläufe usw. mit Roh-C-Puffern und -Zeigern zu identifizieren. Neben der MSDN-Dokumentation zu SAL können Sie auch diesen Blogpost lesen.
Jemand hat ironischerweise (und fälschlicherweise) geschrieben:
"Im Rest der Welt sind Eingaben konstante Zeiger, aber ich nehme an, das war zu einfach. :)"
ohne die Tatsache zu beachten, dass SAL mächtiger ist als das. Tatsächlich können Sie mit SAL auch die maximale Größe eines Ziel-Puffers angeben und angeben, welcher Parameter die Größe des Ziel-Puffers enthält; zum Beispiel, wenn Sie das -Header öffnen, können Sie lesen, dass die tatsächlichen SAL-Annotationen, die für StringCbPrintfW
(die Unicode-Version von StringCbPrintf
) verwendet werden, ungefähr so aussehen:
STRSAFEAPI
StringCbPrintfW(
__out_bcount(cbDest) STRSAFE_LPWSTR pszDest,
__in size_t cbDest,
__in __format_string STRSAFE_LPCWSTR pszFormat,
...)
{
....
Beachten Sie, wie die __out_bcount(cbDest)
SAL-Annotation, die auf den Parameter pszDest
angewendet wird, angibt, dass dies ein Zeiger auf einen Ausgabe-Puffer (__out
) ist, dessen Größe in Bytes (_bcount
) durch den Parameter cbDest
ausgedrückt wird. Wie Sie sehen können, handelt es sich hier um eine umfangreiche Annotation (reichhaltiger als einfach "const
" oder "nicht const
").
Nach meiner Meinung ist SAL ziemlich nutzlos, wenn Sie C++-Code mit robusten Containerklassen wie std::vector
oder std::string
schreiben, die ihre eigene Größe kennen usw. Aber SAL kann in C-ähnlichem Code mit Rohzeigern (wie mehreren Win32-APIs) nützlich sein.
Zur zweiten Hälfte Ihrer Frage:
"Warum benötigen wir StringCbPrintf
, wenn wir bereits sprintf
haben?"
Der Hauptgrund dafür ist, dass sprintf
eine unsichere und anfällige Funktion für Pufferüberläufe ist; stattdessen müssen Sie bei StringCbPrintf
die maximale Größe des Zielpuffers angeben, und dies kann dazu beitragen, Pufferüberläufe zu verhindern (die Sicherheitsfeinde sind).