C中空指针的指针算法

时间:2010-08-19 15:05:28

标签: c pointers void-pointers pointer-arithmetic

当指向特定类型(例如intcharfloat,..)的指针递增时,其值会增加该数据类型的大小。如果指向大小为void的数据的x指针递增,那么如何指向前面的x字节?编译器如何知道将x添加到指针的值?

8 个答案:

答案 0 :(得分:248)

最终结论:C和C ++中void*的算术非法

GCC允许它作为扩展,请参阅Arithmetic on void- and Function-Pointers(请注意,本节是本手册“C扩展”一章的一部分)。为了与GCC兼容,Clang和ICC可能允许void*算术。其他编译器(如MSVC)不允许对void*进行算术运算,如果指定了-pedantic-errors标志,或者指定了-Werror-pointer-arith标志,则GCC不允许运算(如果您的代码有用,则此标志很有用) base也必须使用MSVC编译。

C标准发言

报价取自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)具有相同的含义xchar*还是void*,但这并不意味着您可以对{{{{{ 1}}。

编者注:此答案已经过编辑,以反映最终结论。

答案 1 :(得分:56)

void*指针不允许使用指针运算。

答案 2 :(得分:16)

将它强制转换为char指针,指针向前转x字节前进。

答案 3 :(得分:14)

出于这个原因,你不能对void *类型进行指针算术!

答案 4 :(得分:10)

C标准不允许 void 指针算术。但是,考虑到 void 的大小为 var context = new Model1(); var dbSet = context.Set<A>(); var dbSet1 = context.Set<B>(); var a = dbSet.Find(1); var b = a.B; b.title = DateTime.Now.Ticks.ToString(); int changes1 = context.SaveChanges(); if (changes1 == 0) throw new Exception("not updated"); ,允许 GNU C

C11标准§6.2.5

第 - 19段

  

1类型包含一组空值;这是一个不完整的   无法完成的对象类型

以下程序在GCC编译器中正常工作。

void

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

答案 5 :(得分:8)

在进行指针运算之前,必须将其强制转换为其他类型的指针。

答案 6 :(得分:5)

Void指针可以指向任何内存块。因此,当我们在void指针上尝试指针运算时,编译器不知道要递增/递减多少字节。因此,void指针必须首先被类型转换为已知类型,然后才能参与任何指针算法。

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.

答案 7 :(得分:0)

编译器通过类型转换知道。给定void *x

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

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