指针C中的空指针的指针运算
当一个指向特定types(比如int
, char
, float
,…)的指针递增时,它的值就会增加该数据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:
void
types包含一组空值; 这是一个不完整的types,不能完成。
由于void
是一个不完整的types,它不是一个对象types。 因此它不是一个加法操作的有效操作数。
因此你不能在void
指针上执行指针运算。
笔记
原来,由于C标准的这些部分,认为void*
算术是被允许的:
6.2.5-27:指向void的指针与指向字符types的指针具有相同的表示和alignment要求。
然而,
相同的表示和alignment要求旨在将可互换性作为参数,从函数返回值以及联合成员。
所以这意味着printf("%s", x)
具有相同的含义,无论x
types是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+1
向x
增加一个字节,指针转到字节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; }
可能是其他编译器产生错误。