指针C中的空指针的指针运算

当一个指向特定types(比如intcharfloat ,…)的指针递增时,它的值就会增加该数据types的大小。 如果一个指向大小为x数据的void指针递增,它如何指向前面的x个字节? 编译器如何知道将x添加到指针的值?

最后的结论:在void*上的算术在C和C ++都是非法的

GCC允许它作为扩展,参见void函数指针上的算术 (请注意,本节是本手册“C扩展”一章的一部分)。 为了与GCC兼容,Clang和ICC可能允许void*算术。 其他编译器(例如MSVC)不允许对void*算术运算,如果指定了-pedantic-errors标志,或者指定了-Werror-pointer-arith标志,GCC将不允许使用该标志(如果你的代码库也必须用MSVC编译)。

C标准讲话

行情来自n1256草案。

标准对加法操作的描述如下:

6.5.6-2:另外,两个操作数都应该有算术types,或者一个操作数应该是一个指向对象types的指针,另一个操作数应该是整型。

所以,这里的问题是void*是否是指向“对象types”的指针,或者等价于void是否是“对象types”。 “对象types”的定义是:

6.2.5.1types被划分为对象types (完全描述对象的types ), 函数types (描述函数的types)和不完整types (描述对象的types,但缺less确定其大小所需的信息)。

标准将void定义为:

6.2.5-19: voidtypes包含一组空值; 这是一个不完整的types,不能完成。

由于void是一个不完整的types,它不是一个对象types。 因此它不是一个加法操作的有效操作数。

因此你不能在void指针上执行指针运算。

笔记

原来,由于C标准的这些部分,认为void*算术是被允许的:

6.2.5-27:指向void的指针与指向字符types的指针具有相同的表示和alignment要求。

然而,

相同的表示和alignment要求旨在将可互换性作为参数,从函数返回值以及联合成员。

所以这意味着printf("%s", x)具有相同的含义,无论xtypes是char*还是void* ,但这并不意味着您可以对void*进行算术运算。

编者按:这个答案已经被编辑,以反映最后的结论。

指针运算在void*指针上是不允许的。

正因为如此,你不能在void *types上做指针运算。

将其转换为char指针,将指针向前增加x个字节。

在做指针运算之前,你必须把它转换成另一种types的指针。

空指针可以指向任何内存块。 因此,当我们尝试在void指针上进行指针运算时,编译器不知道要增加或减less多less个字节。 因此,void指针必须首先被转换为一个已知types,然后才能涉及任何指针运算。

 void *p = malloc(sizeof(char)*10); p++; //compiler does how many where to pint the pointer after this increment operation char * c = (char *)p; c++; // compiler will increment the c by 1, since size of char is 1 byte. 

编译器通过types转换知道。 给定一个void *x

  • x+1x增加一个字节,指针转到字节x+1
  • (int*)x+1添加sizeof(int)字节,指针转到字节x + sizeof(int)
  • (float*)x+1地址sizeof(float)字节等

尽pipe第一项不是可移植的,并且不符合C / C ++的Galateo,但它仍然是C语言正确的,这意味着它将编译成大多数编译器上的某些东西,可能需要适当的标志(如-Wpointer-arith)

C标准不允许void指针算术。 但是,考虑到void的大小是1允许GNU C。

C11标准§6.2.5

第19段

voidtypes包含一组空值; 这是一个不完整的对象types,不能完成。

下面的程序在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; } 

可能是其他编译器产生错误。