当指向特定类型(例如int, char, float, ..)的指针增加时,其值将按该数据类型的大小增加。如果指向大小为x的数据的空指针被增加,它如何提前x字节指向?编译器如何知道将x添加到指针的值?
当前回答
将其转换为char型指针,使指针向前增加x字节。
其他回答
C标准不允许空指针运算。然而,考虑到void的大小为1,GNU C是允许的。
C11标准§6.2.5
第19段
void类型由一组空值组成;这是一个不完整的 无法完成的对象类型。
以下程序在GCC编译器中工作良好。
#include<stdio.h>
int main()
{
int arr[2] = {1, 2};
void *ptr = &arr;
ptr = ptr + sizeof(int);
printf("%d\n", *(int *)ptr);
return 0;
}
可能是其他编译器产生错误。
你不能在void *类型上做指针算术,正是因为这个原因!
最后的结论:在C和c++中,对void*的运算都是非法的。
GCC允许它作为一个扩展,参见算术关于void-和function - pointer(注意,这部分是手册的“C Extensions”章节的一部分)。Clang和ICC可能为了与GCC兼容而允许void*算法。其他编译器(如MSVC)不允许对void*进行算术运算,如果指定了-pedantic-errors标志,或者指定了-error -pointer-arith标志,GCC就不允许对void*进行算术运算(如果你的代码基也必须使用MSVC编译,这个标志很有用)。
C标准说话
引用自n1256草案。
该标准对加法运算状态的描述:
6.5.6-2:对于加法,两者都可以 操作数应具有算术类型, 或者一个操作数是指向的指针 一个对象类型,另一个应该 具有整型。
所以,这里的问题是void*是否是一个指向“对象类型”的指针,或者等效地,void是否是一个“对象类型”。“对象类型”的定义是:
6.2.5.1:类型被划分为对象类型(完全描述对象的类型)、函数类型(描述函数的类型)和不完整类型(描述对象但缺乏确定其大小所需信息的类型)。
标准将void定义为:
6.2.5-19:虚空类型包括 一组空值; 它是一个不完全类型,不能 完成。
由于void是不完全类型,所以它不是对象类型。因此,它不是加法运算的有效操作数。
因此,不能在空指针上执行指针算术。
笔记
最初,人们认为void*算术是允许的,因为C标准的这些部分:
6.2.5-27:指向void的指针应具有相同的表示和对齐方式 的指针 字符类型。
然而,
相同的表示和对齐方式 需求意味着暗示 作为参数的互换性 函数,返回值 职能和工会成员。
因此,这意味着printf("%s", x)无论x的类型是char*还是void*都具有相同的含义,但这并不意味着您可以对void*进行算术运算。
在进行指针算术之前,必须将它强制转换为另一种类型的指针。
编译器通过类型转换知道。给定一个void *x:
X +1向X增加一个字节,指针指向字节X +1 (int*)x+1添加sizeof(int)字节,指针指向字节x+ sizeof(int) (float*)x+1地址sizeof(float)字节, 等。
尽管第一项是不可移植的,并且反对C/ c++的Galateo,但它仍然是C语言正确的,这意味着它将在大多数编译器上编译成可能需要适当标志的东西(如-Wpointer-arith)