1、指针和整数做运算
在C语言中假设P是一个整型的指针,当执行P++时候,P指针指向的地址并不是直接加1,而是加增加了4。这个差异是因为在C语言标准中,加法和减法运算对于地址的操作和对于值的操作是不同的。如下图所示(此处假设一个int是4个字节)。
同理假设P是指向一个大小为size的结构体指针,P++指向的地址实际上向后偏移了size大小的偏移量。减法与加法刚好相反,则是向前移动size大小的偏移量。
结论:当一个加法或减法运算的时候,运算符两边的操作数一个是指针,一个是整数的时候,这个整数值先乘以指针指向的数据类型的大小(如sizeof(int)),然后在和指针的值相加或相减。
2、指针和指针做运算
当一个减法运行,减号两边的操作数都是地址的时候,则这两个地址的数据类型必须一致(如都是int * 类型),否则无法通过编译。减法运算的结果为地址值的差,再除以该地址的数据类型的大小(如size(int))。
如上图所示,(P+2)-(P)表示的最终得到的结果是2。其计算方式是P+2指向的地址减去P指向的地址(等于8),然后再对差值除以P指向的类型大小(4),即8/4=2。
例如在PG中的复制槽管理中就使用该地址运算来索引复制槽的在数组中的位置,具体的代码如下:
int
ReplicationSlotIndex(ReplicationSlot *slot)
{
Assert(slot >= ReplicationSlotCtl->replication_slots &&
slot < ReplicationSlotCtl->replication_slots + max_replication_slots);
return slot - ReplicationSlotCtl->replication_slots;
}
函数中可以发现,两个相同的指针做差得到的结果是一个整数,此处表示获取该复制槽在复制槽数组中的偏移(replication_slots 是数组指针,slot表示数组中的某一元素地址如replication_slots[i])。