254

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 pointer?

5
  • 1
    possible duplicate of Error Performing Pointer Arithmetic on void * in MSVC Commented Aug 19, 2010 at 21:43
  • 5
    The question sounds as though it assumes that the compiler(/run-time) knows what type of object the pointer was set to, and adds its size to the pointer. That is a complete misconception: it only knows the address. Commented May 5, 2015 at 21:22
  • 3
    "If a void pointer which points to data of size x is incremented, how does it get to point x bytes ahead?" It doesn't. Why can't people who have such questions test them before asking - y'know, at least to the bare minimum where they check whether it actually compiles, which this doesn't. -1, can't believe this got +100 and -0. Commented Aug 20, 2016 at 6:30
  • @underscore_d because its a good question. We must know WHY it does not compile. It would be perfectly logical to assume that adding 1 to void * advances address by 1 byte (same as char *). Yet, the stupid illogical standard of it being "illegal" is forced upon everybody for no reason. Commented Jul 18, 2022 at 14:16
  • @ScienceDiscoverer Yes, it is a good question. But the stupidity and illogicality are your opinion. In my opinion, it's perfectly logical that arithmetic on void pointers doesn't work, because in C, p + n obviously has to add n * sizeof(*p) to the address in p, but sizeof(void) is obviously 0. Commented Oct 8, 2022 at 12:06

10 Answers 10

375
+100

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*.

Sign up to request clarification or add additional context in comments.

17 Comments

From the C99 standard: (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.2.5.19) The void type comprises an empty set of values; it is an incomplete type that cannot be completed. I think that makes it clear that void* pointer arithmetic is not allowed. GCC has an extension that allows to do this.
if you no longer think your answer is useful, you can just delete it.
This answer was useful even though it proved wrong as it contains conclusive proof that void pointers aren't meant for arithmetic.
Clang and ICC don't allow void* arithmetic (at least by default).
Oh, but for pointer addition, now "one operand shall be a pointer to a complete object type and the other shall have integer type.". So I guess pointer addition with a void* pointer is still undefined behavior.
|
74

Pointer arithmetic is not allowed on void* pointers.

4 Comments

+1 Pointer arithmetic is only defined for pointers to (complete) object types. void is an incomplete type that can never be completed by definition.
@schot: Exactly. Moreover, pointer arithmetic is only defined on a pointer to an element of an array object and only if the result of the operation would be a pointer to an element in that same array or one past the last element of that array. If those conditions are not met, it is undefined behavior. (From C99 standard 6.5.6.8)
Apparently it is not so with gcc 7.3.0. Compiler accepts p + 1024, where p is void*. And result is the same as ((char *)p) + 1024
@zzz777 it's a GCC extension, see the link in the top voted answer.
30

cast it to a char pointer an increment your pointer forward x bytes ahead.

3 Comments

If you are writing your sort function, which according to man 3 qsort should have the void qsort(void *base, size_t nmemb, size_t size, [snip]), then you have no way of knowing the "right type"
Also, if you are writing something like the Linux kernel's container_of macro, then you need a way to compensate for different compilers' packing of structs. For example, given this struct: ... typedef struct a_ { x X; y Y; } a; ... If you then have a variable y *B = (something) and you want a pointer to B's enclosing a struct (presuming it exists), then you end up needing to do something like this: ... a *A = (a*)(((char*)B) - offsetof(a, Y)); ... If you do this instead: ... a *A = (a*)(((x*)B)-1); ... then you may or may not get some very nasty surprises!
@alisianoi it's right there in the signature. It literally says size_t size. So you increment by size*i
26

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.

Comments

15

You can't do pointer arithmetic on void * types, for exactly this reason!

Comments

11

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.

Comments

9

You have to cast it to another type of pointer before doing pointer arithmetic.

Comments

2

[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.

Comments

-1

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

Comments

-3

Compiler knows by type cast. Given a void *x:

  • x+1 adds one byte to x, pointer goes to byte x+1
  • (int*)x+1 adds sizeof(int) bytes, pointer goes to byte x + sizeof(int)
  • (float*)x+1 addres sizeof(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)

2 Comments

Althought the first item is not portable and is against the Galateo of C/C++ True. it is nevertheless C-language-correct False. This is doublethink! Pointer arithmetic on void * is syntactically illegal, should not compile, and produces undefined behaviour if it does. If a careless programmer can make it compile by disabling some warning, that's no excuse.
@underscore_d: I think some compilers used to allow it as an extension, since it's a lot more convenient than having to cast to unsigned char* to e.g. add a sizeof value to a pointer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.