天天看点

【理论实践】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一致

继续阅读