203

当指向特定类型(例如int, char, float, ..)的指针增加时,它的值会增加该数据类型的大小。如果void指向大小数据的指针x递增,它如何指向x前面的字节?编译器如何知道添加x指针的值?

4

9 回答 9

326

最终结论:对 a 的算术在C 和 C++ 中都是void*非法的。

GCC 允许它作为扩展,请参阅Arithmetic on void- 和 Function-Pointers(请注意,本节是手册“C 扩展”一章的一部分)。void*为了与 GCC 兼容,Clang 和 ICC 可能允许算术。其他编译器(例如 MSVC)不允许对 进行算术运算void*,如果-pedantic-errors指定了标志,或者指定了-Werror-pointer-arith标志(如果您的代码库也必须使用 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)具有相同的含义,但这并不意味着您可以对 a 进行算术运算。xchar*void*void*

于 2010-08-19T17:05:39.960 回答
66

指针上不允许指针算术void*

于 2010-08-19T15:06:47.150 回答
27

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

于 2010-08-19T15:08:25.233 回答
18

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

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;
}

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

于 2017-09-15T11:37:23.423 回答
14

void *正是因为这个原因,您不能对类型进行指针运算!

于 2010-08-19T15:08:20.037 回答
8

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.
于 2013-01-22T05:42:17.903 回答
8

在进行指针运算之前,您必须将其转换为另一种类型的指针。

于 2010-08-19T15:08:36.497 回答
-1

void 指针中不允许指针算术。

原因:指针算术与普通算术不同,因为它是相对于基地址发生的

解决方案:在算术时使用类型转换运算符,这将使执行指针算术的表达式知道基本数据类型。例如:point 是 void 指针

*point=*point +1; //Not valid
*(int *)point= *(int *)point +1; //valid
于 2021-10-21T12:56:52.470 回答
-3

编译器通过类型转换知道。给定一个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)

于 2015-03-13T09:40:19.560 回答