一、stddef.h头文件

  • 该头文件定义了各种变量类型和宏。这些定义中的大部分也出现在其它头文件中

二、ptrdiff_t数据类型

  • 这是有符号整数类型,它是两个指针相减的结果
  • ptrdiff_t通常被定义为long int类型
  • 与size_t的区别:
  • 因为size_t通常用来表示数组的长度等,所以size_t必须是一个正数所以被设计为unsigned类型
  • ptrdiff_t应保证足以存放同一数组中两个指针之间的差距,而距离有可能是负数,所以被设计为signed类型


演示案例

#include <cstddef>
#include <iostream>

using std::cout;
using std::cin;
using std::endl;

int main()
{
int arr[4]={1,2,3,4};

std::ptrdiff_t len1=arr[3]-arr[0];
std::ptrdiff_t len2=arr[0]-arr[3];

std::cout<<"arr[3]-arr[0] is "<<len1<<std::endl;
std::cout<<"arr[0]-arr[3] is "<<len2<<std::endl;

return 0;
}

C++:45---stddef.h头文件(ptrdiff_t、size_t、wchar_t数据类型、NULL、offsetof宏)_ptrdiff_t


三、size_t数据类型

  • 它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小
  • 使用场景:
  • 例如,bitset的size操作返回bitset对象中二进制位中1的个数,返回值类型是size_t
  • 例如:在用下标访问元素时,vector使用vector::size_type作为下标类型,而数组下标的正确类型则是size_t。vector使用的下标实际也是size_t,源码是typedef size_t size_type
  • sizeof运算符的返回值就是size_t类型


定义:

C语言系统使用typedef将unsigned  int或unsigned  long定义为size_t

  • typedef  unsigned   int     size_t;
  • typedef  unsigned   long  size_t;

C++:45---stddef.h头文件(ptrdiff_t、size_t、wchar_t数据类型、NULL、offsetof宏)_offsetof_02



实现方式、可移植性

  • 在C++中,设计size_t 就是为了适应多个平台的。size_t的引入增强了程序在不同平台上的可移植性
  • size_t是针对系统定制的一种数据类型,一般是整型,因为C/C++标准只定义一最低的位数,而不是必需的固定位数。而且在内存里,对数的高位对齐存储还是低位对齐存储各系统都不一样。为了提高代码的可移植性,就有必要定义这样的数据类型。一般这种类型都会定义到它具体占几位内存等。当然,有些是编译器或系统已经给定义好的。经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性



  • 使用size_t时,编辑器会根据不同的系统替换标准类型
  • 可以使用%zd打印size_t的类型。如果不支持%zd,还可以使用%u、%lu



关于size_t在for等循环中的一个注意事项

  • 因为size_t是一个无符号类型,因此其的值永远都是大于0的
  • 看下面一个for循环,其在条件中使用size_t的数据类型进行递减,但是由于size_t的数永远都是大于0的,因此for循环的"n>=0"的条件永远为真,因此for循环可能会永远执行下去

vector<int> g_clients;

for (size_t n = g_clients.size() - 1; n >= 0; --n)
{
//...
}

  • 有些编译器可能会给出警告,有些编译器可能会直接报错
  • 正确的做法是将上面的g_clients.size()返回值转换为int,代码如下:

vector<int> g_clients;

for (int n = (int)g_clients.size() - 1; n >= 0; --n)
{
//...
}



四、wchar_t数据类型

  • 这是一个宽字符常量大小的整数类型

五、NULL宏

  • 这个宏是一个空指针常量的值

六、offsetof宏

  • 是一个结构成员定位宏,在另外一篇文章详细介绍过​