天天看點

【理論實踐】size_t和std:size_t可能是不同的類型定義,隻是定義為相同的類型

這個很少被人意識到,2個分别對應到c頭檔案定義和c++頭檔案定義,日常使用沒有影響是因為先包含的會使後續包含定義觸發條件編譯,而且經常using namespace std;使不區分std:size_t。做為一個優秀的代碼輸出者,要嚴謹的弄清楚,有針對性的處理,提高代碼品質,降低代碼開發周期。

結論:c和C++混編,尤其是跨平台時,一定要注意頭檔案包含順序,如果是c++,最早的包含c++的頭檔案,如果是c,則晚一些包含c++頭檔案,這是有差異的,不保證完全等價。

第一部分,影響:

對于業務邏輯,包括typeid等,都沒有影響,因為條件編譯是預處理階段完成,編譯階段面對的已經是基礎類型定義。

但是,畢竟兩個檔案是獨立的,在跨平台編譯等情況下,類型定義僅為了保證長度相等,兩個檔案可能會産生定義差異,導緻類型不比對,比如

#include <iostream>
#include <typeinfo>
using namespace std;

typedef long long  type1;
typedef int64_t type2;

int main()
{
        type1 s1 = 0;
        type2 s2 = 0;
        cout << sizeof(type1) << " " << sizeof(type2) << endl;
        cout << (typeid(s1) == typeid(s2) ? "eq" : "nq") << endl;
        cout << typeid(s1).name() << endl;
        cout << typeid(s2).name() << endl;
        return 0;
}
輸出
8 8
nq
x
l
           

這與邏輯是對不上的,位長一樣,符号一樣,卻是不同的類型。

第二部分,驗證一下差別,通過将size_t重定義産生沖突報錯來檢視定義源

#include <stdio.h>
typedef bool size_t;
int main()
{
                return 0;
}
           

編譯報錯:

main.cpp:3:14: error: conflicting declaration ‘typedef bool size_t’

 typedef bool size_t;

              ^

In file included from /usr/include/stdio.h:34:0,

                 from main.cpp:1:

/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/stddef.h:212:23: error: ‘size_t’ has a previous declaration as ‘typedef long unsigned int size_ ’

 typedef __SIZE_TYPE__ size_t;

                       ^

make: *** [main] Error 1

繼續追蹤:

/opt/rh/devtoolset-2/root/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include/stddef.h:209:#define __SIZE_TYPE__ long unsigned int

是以C頭檔案定義是:long unsigned int

再來看一下c++定義

#include <iostream>
using namespace std;
namespace std
{
        typedef bool size_t;
}
int main()
{
        return 0;
}
           

編譯報錯

main.cpp:7:15: error: conflicting declaration ‘typedef bool std::size_t’

  typedef bool size_t;

               ^

In file included from /opt/rh/devtoolset-2/root/usr/include/c++/4.8.2/iostream:38:0,

                 from main.cpp:2:

/opt/rh/devtoolset-2/root/usr/include/c++/4.8.2/x86_64-redhat-linux/bits/c++config.h:1857:26: error: ‘std::size_t’ has a previous declaration as ‘typedef long unsigned int std::size_t’

   typedef __SIZE_TYPE__  size_t;

                          ^

make: *** [main] Error 1

進一步追蹤:

bits/c++config.h:1764 if __cplusplus

...

bits/c++config.h:1855 namespace std

{

          typedef __SIZE_TYPE__     size_t;

            typedef __PTRDIFF_TYPE__  ptrdiff_t;

#if __cplusplus >= 201103L

                  typedef decltype(nullptr) nullptr_t;

#endif

}

這個做法非常聰明,直接使用了系統的__SIZE_TYPE__,是以必然和C一緻

繼續閱讀