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 void
pointer which points to data of size x
is incremented, how does it get to point x
bytes ahead? How does the compiler know to add x
to value of the poin开发者_开发知识库ter?
Final conclusion: arithmetic on a void*
is illegal in both C and 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-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).
The C Standard Speaks
Quotes are taken from the n1256 draft.
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.
So, the question here is whether void*
is a pointer to an "object type", or equivalently, whether void
is an "object type". 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).
And the standard defines void
as:
6.2.5-19: The
void
type comprises an empty set of values; it is an incomplete type that cannot be completed.
Since void
is an incomplete type, it is not an object type. Therefore it is not a valid operand to an addition operation.
Therefore you cannot perform pointer arithmetic on a void
pointer.
Notes
Originally, it was thought that void*
arithmetic was permitted, because of these sections of the C standard:
6.2.5-27: A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.
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*
.
Pointer arithmetic is not allowed on void*
pointers.
cast it to a char pointer an increment your pointer forward x bytes ahead.
The C standard does not allow void pointer arithmetic. However, GNU C is allowed by considering the size of void is 1
.
C11 standard §6.2.5
Paragraph - 19
The
void
type comprises an empty set of values; it is an incomplete object type that cannot be completed.
Following program is working fine in GCC compiler.
#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.
You can't do pointer arithmetic on void *
types, for exactly this reason!
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 *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.
You have to cast it to another type of pointer before doing pointer arithmetic.
[answer copied from a comment on a later, duplicate question]
Allowing arithmetic on void pointers is a controversial, nonstandard extension. If you're thinking in assembly language, where pointers are just addresses, arithmetic on void pointers makes sense, and adding 1 just adds 1. But if you're thinking in C terms, using C's model of pointer arithmetic, adding 1 to any pointer p
actually adds sizeof(*p)
to the address, and this is what you want pointer arithmetic to do, but since sizeof(void)
is 0, it breaks down for void pointers.
If you're thinking in C terms you don't mind that it breaks down, and you don't mind inserting explicit casts to (char *)
if that's the arithmetic you want. But if you're thinking in assembler you want it to just work, which is why the extension (though a departure from the proper definition of pointer arithmetic in C) is desirable in some circles, and provided by some compilers.
Pointer arithmetic is not allowed in the void pointer.
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 +1; //Not valid
*(int *)point= *(int *)point +1; //valid
Compiler knows by type cast. Given a void *x
:
x+1
adds one byte tox
, pointer goes to bytex+1
(int*)x+1
addssizeof(int)
bytes, pointer goes to bytex + sizeof(int)
(float*)x+1
addressizeof(float)
bytes, etc.
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)
精彩评论