1. 程式人生 > >protobuf無法使用open函式開啟檔案

protobuf無法使用open函式開啟檔案

說了一大堆就是說open函式在Windows下的在io.h標頭檔案下,Linux下的在fcntl.h標頭檔案下。同時若直接使用這個,則vs編譯會提示error C4996: 'open': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _open. See online help for details.
這是因為在vs下open函式已經被廢棄,vs建議使用_open但使用_open又會出現error C4996: '_open': This function or variable may be unsafe. Consider using _sopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

在工程設定裡預編譯頭加上_CRT_SECURE_NO_WARNINGS即可不關心原因看到這裡就結束了。

今天在使用protobuf做簡單的引數存取時發現,Windows下無法使用open函式獲取檔案描述符

open 函式用於開啟和建立檔案。以下是 open 函式的簡單描述

#include <fcntl.h>
int open(const char *pathname, int oflag, ... );

於是查了下。

在Linux下open函式是在fcntl.h標頭檔案中的(該標頭檔案中包含了許多檔案開啟的模式定義和create、fcntl、open等函式),windows也有該標頭檔案(但僅包含了一些檔案開啟模式的定義)。

因此判定fcntl.h並不是標準庫函式。查了下,果然如此(不得不說基礎知識掌握不牢固啊)。

該標頭檔案不屬於標準庫函式,且Windows下的fcntl.h標頭檔案下沒有該函式並不代表這個功能不能用,或者Windows下不能使用這個功能。畢竟protobuf就提供了這個介面。

查了寫資料,有人說FILE結構體中包含了檔案描述符這個欄位,其形式如下(其中_file就是Linux下的檔案描述符fd):

struct _iobuf {  
      char *_ptr; 
      int _cnt; 
      char *_base; 
      int _flag; 
      int
_file;//檔案描述符
     int _charbuf;      int _bufsiz;      char *_tmpfname; };   typedef struct _iobuf FILE;  

但是我在VS2015下查找了下,發現其實現形式並非如此,而是這樣:

//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Stream I/O Declarations Required by this Header
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#ifndef _FILE_DEFINED
    #define _FILE_DEFINED
    typedef struct _iobuf
    {
        void* _Placeholder;
    } FILE;
#endif

因此認為應該是編譯環境升級導致資料結構與原先發生了一些改變,無法使用(瞎猜的)。

後查閱資料發現vs下可用io.h標頭檔案中的open函式實現獲取檔案描述符的功能

C標準庫

C標準庫,顧名思義既然是標準,就是由標準組織制定的。

是由“美國國家標準協會(American National Standards Institute,ANSI)”為了規範C語言庫而制定的標準。在最初,各個大學各個公司使用的C語言庫都不盡相同,造成相互移植非常困難,在這個背景下,制定了這個標準。

下面是標準庫函式的標頭檔案:

標準頭名 功能 描述
<assert.h> 診斷 僅包含assert巨集。可以在程式中使用該巨集來診斷程式狀態(例如某個變數是否為0等),若檢查失敗,程式終止。
<ctype.h> 字元處理 包含判斷字元型別及大小寫轉換的函式。
<errno.h> 錯誤監測 提供了errno。可以在呼叫特定庫函式後檢測errno的值以判斷呼叫過程中是否有錯誤發生。
<float.h> 浮點數特性 提供了描述浮點數特性的巨集。
<limits.h> 整型特性 提供了描述整數型別和字元型別特性的巨集。
<locale.h> 本地化 提供了一些支援程式國際化的函式。
<math.h> 數學計算 提供了大量用以數學計算的函式。
<setjmp.h> 非本地跳轉 提供了用於繞過正常的函式返回機制,從一個函式跳轉到另一個正在活動的函式的setjmplongjmp函式。
<signal.h> 訊號處理 提供了包括中斷和執行時錯誤在內的異常情況處理函式。
<stdarg.h> 不定引數 提供了支援函式處理不變個數的引數的工具。
<stddef.h> 常用定義 提供了常用的型別和巨集。
<stdio.h> 輸入輸出 提供了大量輸入輸出函式。
<stdlib.h> 常用實用函式 提供了大量實用的函式。
<string.h> 字串處理 提供了大量字串處理函式。
<time.h> 日期和時間 提供了獲取、操縱和處理日期的函式。

C執行庫

C執行庫,是和平臺相關的,即和作業系統相關的。

它由不同作業系統不同開發平臺提供不同的C執行庫。但是C執行庫的部分實現是基於C標準庫的,即C執行庫是各個作業系統各個開發工具根據自身平臺開發的庫,某種程度上,可以說C執行庫是C標準庫的一個擴充套件庫,只是加了很多C標準庫所沒有的與平臺相關的或者不相關的庫介面函式。舉例子如:c標準庫的strcpy函式負責字串的拷貝,但是由於缺少對目地字串緩衝區大小的控制,極有可能導致緩衝區溢位(大量的緩衝區溢位攻擊都是由於這種漏洞而產生的);相反,Windows提供了能夠實現同樣功能的安全的字串拷貝函式,減少了緩衝區攻擊的可能,strcpy_s。這些函式是以c執行庫的方式提供的,當然,不同的作業系統,c執行時庫可能不同,但是對c標準庫的支援是完全一致的,也就是說,在不同的作業系統上,使用同一個c標準庫的函式必然產生一致的結果。

一個C執行庫大致包含了如下功能:* 啟動與退出:包括入口函式及入口函式所依賴的其他函式等。
* 標準函式:由C語言標準規定的C語言標準庫所擁有的函式實現。(C標準庫)
* I/O:I/O功能的封裝和實現,參見上一節中I/O初始化部分。
* 堆:堆的封裝和實現,參見上一節中堆初始化部分。
* 語言實現:語言中一些特殊功能的實現。
* 除錯:實現除錯功能的程式碼。
總結一下,C標準庫就是任何平臺都可以使用的基本C語言庫。而CRT除了將C標準庫加入所屬範圍外,還擴充套件了與平臺相關的介面庫,這些介面實現根據不同平臺呼叫不同平臺的作業系統API。

如下圖所示,採用C標準庫編寫的程式可以應用到windows平臺,也可以應用到linux平臺;而用CRT另外與平臺相關的庫函式編寫的應用程式不能跨平臺執行。

參考資料: