為什麼C++的庫函數的定義會這麼複雜?

在學習C++的時候一直有一個困惑,比如cctype中的isblank()函數,自己實現的話大概是這樣:

bool isblank(char a)

{

if (a == " " || a == " ")

return 1;

else

return 0;

}

但是cctype(ctype.h)中是這樣定義的:

_Check_return_ _ACRTIMP int __cdecl isblank(_In_ int _C);

感覺非常不好理解,有很多複雜的宏定義和沒見過的關鍵字,還找不到isblank()的功能具體是在哪裡實現的。為什麼標準庫中函數的定義會這麼複雜?工程中實際寫的C++代碼也是這樣的嗎?


不,C++ 的 & 里,isblank 的聲明是這樣的:

namespace std {
int isblank(int c);
}

題目中的

_Check_return_ _ACRTIMP int __cdecl isblank(_In_ int _C);

只是 MSVC 某個版本的實現。

只要和標準不衝突,實現可以添加自己的東西,或者在任何時候去掉自己添加的這些東西。它們都是實現細節而已。所以建議不要通過看頭文件來學習、分析,好好看文檔吧,就算是看 MSDN 也行。


另外,C++ 為了儘可能兼容 C,C 語言標準庫的函數都是能不改就不改。題目中給出的實現在原型上就有幾個問題:

  • bool 是 C99 才有的東西(還得 include 了 stdbool.h 才能用),所以 C 語言不可能用當時還不存在的 bool 作為返回值類型,所以 C++ 也選擇保留 int 返回值
  • C 語言 is 系列函數因為需要處理 EOF,而 EOF 與任何有效的 unsigned char 值都不同(通常是 -1),所以不能使用 char 系列類型,而是用 int 型。


我看過 Windows 源碼里一些頭文件,可以明確告訴你,工程里有過之而無不及。

_Check_return_ 和 _In_ 這兩個宏屬於 SAL(https://docs.microsoft.com/en-us/visualstudio/code-quality/understanding-sal),可以幫助編譯器在編譯期發現下標越界、空指針訪問之類的問題。

__cdecl 這個關鍵字是 VC++ 默認的調用約定(https://docs.microsoft.com/en-us/cpp/cpp/cdecl),因為是默認的所以常常不寫,但當有多種調用約定混在一起的時候就很必要了。

_ACRTIMP 這個宏可以顧名思義,你這個庫函數的實現在 CRT 里,取決於你的編譯姿勢,可能在編譯時鏈接進來的某個 lib 里,也可能在運行時 C:WindowsSystem32 下面的某個 dll 里。


這些都是M$的dll相關擴展搞出來的私貨,本來在C標準里就是 int isblank(int),其他實現(比如glibc)也不會帶這些玩意。

你如果不寫windows程序也不寫準備跨平台(且要不通過cygwin直接上windows)的DLL庫,一般不用管M$的__declspec相關的東西,寫了反倒很影響可讀性。相反,如果你寫的library project準備上MSVC,你就應該準備好__declspec相關的宏。總之扯上MSVC事情就會變煩就是了。

另外,如果你是初學者,想學C或者C++的標準,那麼你不要直接去看某個實現(比如MSVC的c標準庫或者glibc),那只是一種實現。當然直接看標準效率太低。這裡推薦 cppreference.com 。


那些你不認識的東西都不是語言本身的東西。你可以理解成是某種給讀者和分析工具用的注釋。你現在看了不習慣,等過幾年你就會慢慢體會到這些東西的意義了。

至於說在實際的工程項目中是不是也這麼寫,這個通常取決於項目里的約定和工具。我可以這麼說,或多或少都有一些類似的,但未必和vc的一樣。

你現在主要的問題是不明白這些東西的作用和目的,代碼寫的多一些時候就會慢慢明白。


插個題外話。其實你的isblank沒實現對。除了space,還有tab也算blank。


很多是給靜態分析程序用的符號


如果是VS的話,你應該可以在安裝目錄里找到源碼。

例如C:Program Files (x86)Windows Kits10Source10.0.15063.0ucrtconvert\_ctype.cpp


推薦閱讀:

如何才能寫出沒有bug的程序?
為什麼OJ上有些人提交的代碼運行那麼快? 有人總結這些技巧么
如何解決 C++ 代碼不能打開提示有一個錯誤的問題?
為什麼在 C++ 中,人們經常寫全命名空間,在其他語言卻不呢?
既然編譯器可以判斷一個函數是否適合 inline,那還有必要自己加 inline 關鍵字嗎?

TAG:編程 | C | MicrosoftVisualStudio |