当一个指针到特定类型的(比如int
,char
,float
,..)被递增,其值增加该数据类型的大小。如果void
指向大小数据的指针x
增加了,它如何指向x
前面的字节?编译器如何知道要增加x
指针的值?
void
指向大小数据的指针x
增加了,它如何指向x
前面的字节?” 没有。遇到此类问题的人为什么不能在问之前对其进行测试-知道,至少要检查他们是否真正编译时才达到最低要求,而事实并非如此。-1,简直不敢相信这有+100和-0。
当一个指针到特定类型的(比如int
,char
,float
,..)被递增,其值增加该数据类型的大小。如果void
指向大小数据的指针x
增加了,它如何指向x
前面的字节?编译器如何知道要增加x
指针的值?
void
指向大小数据的指针x
增加了,它如何指向x
前面的字节?” 没有。遇到此类问题的人为什么不能在问之前对其进行测试-知道,至少要检查他们是否真正编译时才达到最低要求,而事实并非如此。-1,简直不敢相信这有+100和-0。
Answers:
最终结论:在C和C ++中,对a进行算术void*
都是非法的。
GCC允许它作为扩展,请参见-和函数指针上的算术void
(请注意,本节是本手册“ C扩展”一章的一部分)。Clang和ICC可能void*
出于与GCC兼容的目的而允许算术。其他编译器(例如MSVC)不允许在上进行算术运算void*
,并且如果-pedantic-errors
指定了-Werror-pointer-arith
标志或指定了标志,则GCC会禁止进行算术运算(如果您的代码库也必须使用MSVC进行编译,则此标志很有用)。
引文摘自n1256草案。
该标准对加法运算的描述为:
6.5.6-2:另外,两个操作数都应具有算术类型,或者一个操作数应是指向对象类型的指针,而另一个应具有整数类型。
因此,这里的问题是void*
指向“对象类型”的指针,或者等效地,是否void
是“对象类型” 的指针。“对象类型”的定义是:
6.2.5.1:类型分为对象类型(完全描述对象的类型),函数类型(描述函数的类型)和不完整类型(描述对象但缺少确定其大小所需的信息的类型)。
该标准定义void
为:
6.2.5-19:
void
类型包括一组空值;它是无法完成的不完整类型。
由于void
是不完整的类型,因此不是对象类型。因此,它不是加法运算的有效操作数。
因此,您不能对void
指针执行指针算术。
最初,void*
由于C标准的以下部分,人们认为算术是允许的:
6.2.5-27:指向void的指针应与 指向字符类型的指针具有相同的表示和对齐要求。
然而,
相同的表示形式和对齐 要求旨在表示作为函数的参数,函数的返回值和并集成员的可互换性。
因此,这意味着具有类型还是printf("%s", x)
具有相同的含义,但这并不意味着您可以对进行算术运算。x
char*
void*
void*
编者注:该答案经过编辑以反映最终结论。
void*
算术运算(至少默认情况下)。
指针不允许使用指针算术void*
。
void
是不完整的类型,根据定义永远无法完成。
将其强制转换为char指针,将指针向前递增x个字节。
char
递增1。转换为,以递增x
,然后将新值重新解释为其他类型既无意义又不确定。
man 3 qsort
应当具有)void qsort(void *base, size_t nmemb, size_t size, [snip])
,则您将无法知道“正确的类型”
空指针可以指向任何内存块。因此,当我们尝试对空指针进行指针算术运算时,编译器不知道要增加/减少多少字节。因此,空指针必须先被类型转换为已知类型,然后才能参与任何指针算术。
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.
编译器通过类型转换知道。给定一个void *x
:
x+1
向加上一个字节x
,指针指向字节x+1
(int*)x+1
添加sizeof(int)
字节,指针转到字节x + sizeof(int)
(float*)x+1
addres sizeof(float)
字节等尽管第一项不是可移植的,并且与C / C ++的Galateo相对,但它还是C语言正确的,这意味着它将在大多数编译器上编译为某种东西,可能需要适当的标记(例如-Wpointer-arith)
Althought the first item is not portable and is against the Galateo of C/C++
真正。it is nevertheless C-language-correct
假。这是双重考虑!指针算术在void *
语法上是非法的,不应进行编译,并且在这样做时会产生未定义的行为。如果粗心的程序员可以通过禁用一些警告来进行编译,那不是借口。
unsigned char*
(例如,将sizeof
值添加到指针)要方便得多。