繁体   English   中英

C中void指针的指针算法

[英]Pointer arithmetic for void pointer in C

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

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

GCC 允许将其作为扩展,参见 关于void和函数指针的算术(注意本节是手册“C 扩展”一章的一部分)。 为了与 GCC 兼容,Clang 和 ICC 可能允许void*算术。 其他编译器(例如 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)无论x类型是char*还是void*都具有相同的含义,但这并不意味着您可以对void*进行算术运算。

void*指针上不允许进行指针运算。

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

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

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

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

您不能对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.

void 指针中不允许进行指针运算。

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

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

*point=*point +1; //Not valid
*(int *)point= *(int *)point +1; //valid

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM