C语言 C中void指针的指针算法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3523145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pointer arithmetic for void pointer in C
提问by Siva Sankaran
When a pointer to a particular type (say int, char, float, ..) is incremented, its value is increased by the size of that data type. If a voidpointer which points to data of size xis incremented, how does it get to point xbytes ahead? How does the compiler know to add xto value of the pointer?
当一个指针到特定类型的(比如int,char,float,..)被递增,其值增加该数据类型的大小。如果void指向大小数据的指针x递增,它如何指向x前面的字节?编译器如何知道要添加x到指针的值?
回答by M. Sadeq H. E.
Final conclusion: arithmetic on a void*is illegalin 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). Clang and ICC likely allow void*arithmetic for the purposes of compatibility with GCC. Other compilers (such as MSVC) disallow arithmetic on void*, and GCC disallows it if the -pedantic-errorsflag is specified, or if the -Werror-pointer-arithflag is specified (this flag is useful if your code base must also compile with MSVC).
GCC 允许将其作为扩展,参见Arithmetic on void- 和 Function-Pointers(注意本节是手册“C 扩展”一章的一部分)。void*为了与 GCC 兼容,Clang 和 ICC 可能允许进行算术运算。其他编译器(例如 MSVC)不允许在 上进行算术运算void*,如果-pedantic-errors指定了标志,或者指定了-Werror-pointer-arith标志(如果您的代码库也必须使用 MSVC 编译,则此标志很有用),GCC 禁止它。
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 voidis an "object type". The definition for "object type" is:
所以,这里的问题是是否void*是指向“对象类型”的指针,或者等价地,是否void是“对象类型”。“对象类型”的定义是:
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 voidas:
标准定义void为:
6.2.5-19: The
voidtype comprises an empty set of values; it is an incomplete type that cannot be completed.
6.2.5-19:
void类型包含一组空值;它是无法完成的不完整类型。
Since voidis an incomplete type, it is not an object type. Therefore it is not a valid operand to an addition operation.
由于void是不完整类型,因此它不是对象类型。因此,它不是加法运算的有效操作数。
Therefore you cannot perform pointer arithmetic on a voidpointer.
因此,您不能对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 alignmentrequirements as a pointer to a character type.
6.2.5-27:指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。
However,
然而,
The same representation and alignmentrequirements 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 xhas type char*or void*, but it does not mean that you can do arithmetic on a void*.
因此,这意味着printf("%s", x)无论是否x具有类型char*或void*,都具有相同的含义,但这并不意味着您可以对 a 进行算术运算void*。
Editor's note:This answer has been edited to reflect the final conclusion.
编者注:此答案已被编辑以反映最终结论。
回答by Job
Pointer arithmetic is not allowed on void*pointers.
指针上不允许进行指针运算void*。
回答by Ultimate Gobblement
cast it to a char pointer an increment your pointer forward x bytes ahead.
将其强制转换为 char 指针,将您的指针向前增加 x 个字节。
回答by msc
The C standarddoes not allow voidpointer arithmetic. However, GNU Cis allowed by considering the size of voidis 1.
在C标准不允许空指针运算。然而,GNU C是考虑大小允许空IS 1。
C11 standard §6.2.5
C11 标准 §6.2.5
Paragraph - 19
第 19 段
The
voidtype comprises an empty set of values; it is an incomplete object typethat cannot be completed.
该
void类型包含一组空值;它是无法完成的不完整对象类型。
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.
可能是其他编译器产生错误。
回答by Oliver Charlesworth
You can't do pointer arithmetic on void *types, for exactly this reason!
您不能对void *类型进行指针运算,正是出于这个原因!
回答by Jakob
You have to cast it to another type of pointer before doing pointer arithmetic.
在进行指针运算之前,您必须将其转换为另一种类型的指针。
回答by Jakob
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. Therefore void pointers must be first typecast to a known type before they can be involved in any pointer arithmetic.
空指针可以指向任何内存块。因此,当我们尝试对 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.
回答by rytis
Compiler knows by type cast. Given a void *x:
编译器通过类型转换知道。给定一个void *x:
x+1adds one byte tox, pointer goes to bytex+1(int*)x+1addssizeof(int)bytes, pointer goes to bytex + sizeof(int)(float*)x+1addressizeof(float)bytes, etc.
x+1向 增加一个字节x,指针指向字节x+1(int*)x+1添加sizeof(int)字节,指针指向字节x + sizeof(int)(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)

