简体   繁体   English

C中void指针的指针算法

[英]Pointer arithmetic for void pointer in C

When a pointer to a particular type (say int , char , float , ..) is incremented, its value is increased by the size of that data type.当指向特定类型(例如intcharfloat 、 ..)的指针递增时,其值会增加该数据类型的大小。 If a void pointer which points to data of size x is incremented, how does it get to point x bytes ahead?如果指向大小为x数据的void指针递增,它如何指向前面的x个字节? How does the compiler know to add x to value of the pointer?编译器如何知道将x添加到指针的值?

Final conclusion: arithmetic on a void* is illegal in both C and C++.最终结论:对void*算术在 C 和 C++ 中都是非法的

GCC allows it as an extension, see Arithmetic on void - and Function-Pointers (note that this section is part of the "C Extensions" chapter of the manual). GCC 允许将其作为扩展,参见 关于void和函数指针的算术(注意本节是手册“C 扩展”一章的一部分)。 Clang and ICC likely allow void* arithmetic for the purposes of compatibility with GCC.为了与 GCC 兼容,Clang 和 ICC 可能允许void*算术。 Other compilers (such as MSVC) disallow arithmetic on void* , and GCC disallows it if the -pedantic-errors flag is specified, or if the -Werror-pointer-arith flag is specified (this flag is useful if your code base must also compile with MSVC).其他编译器(例如 MSVC)不允许对void*算术运算,如果指定了-pedantic-errors标志,或者指定了-Werror-pointer-arith标志(如果您的代码库也必须用 MSVC 编译)。

The C Standard Speaks C 标准说话

Quotes are taken from the n1256 draft.引自 n1256 草案。

The standard's description of the addition operation states:该标准对加法运算的描述指出:

6.5.6-2: For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an object type and the other shall have integer type. 6.5.6-2:对于加法,要么两个操作数都为算术类型,要么一个操作数为指向对象类型的指针,另一个操作数为整数类型。

So, the question here is whether void* is a pointer to an "object type", or equivalently, whether void is an "object type".所以,这里的问题是void*是否是指向“对象类型”的指针,或者等价地, void是否是“对象类型”。 The definition for "object type" is: “对象类型”的定义是:

6.2.5.1: Types are partitioned into object types (types that fully describe objects) , function types (types that describe functions), and incomplete types (types that describe objects but lack information needed to determine their sizes). 6.2.5.1:类型分为对象类型(完整描述对象的类型)、函数类型(描述函数的类型)和不完整类型(描述对象但缺少确定其大小所需的信息的类型)。

And the standard defines void as:该标准将void定义为:

6.2.5-19: The void type comprises an empty set of values; 6.2.5-19: void类型包含一组空值; it is an incomplete type that cannot be completed.它是无法完成的不完整类型。

Since void is an incomplete type, it is not an object type.由于void是不完整的类型,因此它不是对象类型。 Therefore it is not a valid operand to an addition operation.因此,它不是加法运算的有效操作数。

Therefore you cannot perform pointer arithmetic on a void pointer.因此,您不能对void指针执行指针运算。

Notes笔记

Originally, it was thought that void* arithmetic was permitted, because of these sections of the C standard:最初,人们认为void*算术是允许的,因为 C 标准的这些部分:

6.2.5-27: A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. 6.2.5-27:指向 void 的指针应具有指向字符类型的指针相同的表示和对齐要求。

However,然而,

The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.相同的表示和对齐要求意味着作为函数的参数、函数的返回值和联合成员的可互换性。

So this means that printf("%s", x) has the same meaning whether x has type char* or void* , but it does not mean that you can do arithmetic on a void* .所以这意味着printf("%s", x)无论x类型是char*还是void*都具有相同的含义,但这并不意味着您可以对void*进行算术运算。

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

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

The C standard does not allow void pointer arithmetic. C 标准不允许指针算术。 However, GNU C is allowed by considering the size of void is 1 .但是,考虑到void的大小为1GNU C是允许的。

C11 standard §6.2.5 C11 标准 §6.2.5

Paragraph - 19第 19 段

The void type comprises an empty set of values; void类型包含一组空值; it is an incomplete object type that cannot be completed.它是无法完成的不完整对象类型

Following program is working fine in GCC compiler.以下程序在 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;
}

May be other compilers generate an error.可能是其他编译器产生错误。

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

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

Void pointers can point to any memory chunk.空指针可以指向任何内存块。 Hence the compiler does not know how many bytes to increment/decrement when we attempt pointer arithmetic on a void pointer.因此,当我们尝试对 void 指针进行指针算术时,编译器不知道要增加/减少多少字节。 Therefore void pointers must be first typecast to a known type before they can be involved in any pointer arithmetic.因此,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.

Pointer arithmetic is not allowed in the void pointer. void 指针中不允许进行指针运算。

Reason : Pointer arithmetic is not the same as normal arithmetic, as it happens relative to the base address .原因:指针算术与普通算术不同,因为它是相对于基址发生的

Solution : Use the type cast operator at the time of the arithmetic, this will make the base data type known for the expression doing the pointer arithmetic.解决方案:在算术时使用类型转换运算符,这将使执行指针算术的表达式的基本数据类型已知。 ex: point is the void pointer例如:point 是空指针

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

Compiler knows by type cast.编译器通过类型转换知道。 Given a void *x :给定一个void *x

  • x+1 adds one byte to x , pointer goes to byte x+1 x+1x增加一个字节,指针指向字节x+1
  • (int*)x+1 adds sizeof(int) bytes, pointer goes to byte x + sizeof(int) (int*)x+1添加sizeof(int)个字节,指针指向字节x + sizeof(int)
  • (float*)x+1 addres sizeof(float) bytes, etc. (float*)x+1地址sizeof(float)字节等。

Althought the first item is not portable and is against the Galateo of C/C++, it is nevertheless C-language-correct, meaning it will compile to something on most compilers possibly necessitating an appropriate flag (like -Wpointer-arith)尽管第一项是不可移植的,并且与 C/C++ 的 Galateo 背道而驰,但它仍然是 C 语言正确的,这意味着它可以在大多数编译器上编译为某些内容,可能需要一个适当的标志(如 -Wpointer-arith)

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

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