1

Is it possible to perform arithmetic operation on void pointer without the use of casting?

If I have a generic function that takes a pointer of unknown type and an integer specifying the size of the type. Is it possible to perform some pointer arithmetic with just two arguments?

void* Function( void* ptr, int size);
user385261
  • 4,069
  • 8
  • 26
  • 24

2 Answers2

4

No, because the compiler doesn't know the size of the item(s) the void pointer is pointing to. You can cast the pointer to (char *) to do what you want above.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Using casting to do this is a bad idea these days - some compilers (notably GCC) will fail to spot "alias" pointers, and apply broken optimisations as a result. –  Dec 22 '10 at 08:46
  • Then what would be the good idea to perform casting on void pointer? – user385261 Dec 22 '10 at 08:56
  • @Steve314: Advancing a `void*` pointer by casting to `char*` doesn't break strict aliasing rules (3.10/15). For one thing, the pointer is never dereferenced, so we don't use pointers of different types to access the same memory (which is what "aliasing" actually means), and for another thing `char*` is a legal way to alias anything anyway, even under strict aliasing rules. – Steve Jessop Dec 22 '10 at 10:14
  • @Steve - what's the point of offseting the pointer if you're not then going to read/write something through that offset pointer? I've had problems with similar type-punning code, which is why I changed to using union-based casts in the first place. The GCC manual specifically advises the use of union-based puns. Though it's possible my problem was due to casting to integers rather than `char*` to do the arithmetic, so I could be wrong about `char*` causing problems. –  Dec 22 '10 at 18:51
  • @Steve314: What's the point of offsetting a `void*` pointer at all? The questioner doesn't say. In order to read anything back from a `void*` pointer, somebody somewhere must either have an idea what type was stored there (in which case they can use a compatible type to read back), or else they can read back via `char*` regardless of the original type, since punning with `char` is OK. Pointer arithmetic is not punning. And even if someone later does pun, your code doesn't somehow magically make it OK - the GCC extension only applies if the pun itself is done using a union. – Steve Jessop Dec 22 '10 at 21:43
  • ... So it may be that the questioner does have a problem with strict aliasing in his code, but if so then there is nothing that can be done just to this little part of it, that will fix the problem. – Steve Jessop Dec 22 '10 at 21:52
  • @Steve - offsetting in bytes requires some kind of pun because normally the offset applied is scaled to a multiple of the pointed-to type (the pointer acting like an array). Casting to a char* to do the arithmetic is still a pun - your data is not (necessarily) of type char, so you do that cast for a typesystem-subverting effect. You may be correct in saying I'm wrong - I had the impression (from another question I already referenced) that the union-based pun had standards-based guarantees that a cast-based pun wouldn't, but I don't have access to the standard to check. –  Dec 23 '10 at 03:51
  • 1
    @Steve314: The whole type-punning issue is based on 3.10/15: "If a program *attempts to access the stored value of an object* through an lvalue of other than one of the following types the behavior is undefined: ". There follows a list, including "the dynamic type of the object", and also "char or unsigned char", and also "a union that includes one of the aforementioned types among its members", *but* the standard doesn't allow writing one member of a union and then reading another. C99 *does* allow the latter, as does GCC, which is why the union cast works. – Steve Jessop Dec 23 '10 at 10:17
  • 1
    So OK, just converting the pointer is a type pun, in the sense that the pointer does now refer to the wrong type for the address. But it's OK within the strict aliasing rules as long as you don't access the object, *and even if you do access the object*, it's fine to do so with `char*`. If you want to move a pointer by a certain number of bytes, then casting it to `char*` is more portable than your pun of `void*` with `ptrdiff_t`. Either way, what you then do with the result is at your own risk... – Steve Jessop Dec 23 '10 at 10:18
1
  • Warning - the below is probably misleading. As indicated by others in comments (special thanks to Steve Jessop) the union-based type pun below has no special guarantees in standard C++ compared with cast-based puns, and using casts to char* to do the pointer arithmetic will probably be more portable that using unions to convert to integers.

You need some form of type-punning to do this because of the array-like semantics of pointers in standard C++. I will cheat by using union-based puns...

inline void* Ptr_Add  (void* p1, std::ptrdiff_t p2)
{
  union
  {
    void*          m_Void_Ptr;
    std::ptrdiff_t m_Int;
  } l_Pun;

  l_Pun.m_Void_Ptr =  p1;
  l_Pun.m_Int      += p2;

  return l_Pun.m_Void_Ptr;
}

I have this exact code in my library, along with some others for doing byte-oriented pointer arithmetic and bitwise operations. The union-based puns are there because cast-based puns can be fragile (pointer alias analysis in the optimiser may not spot the alias, so the resulting code misbehaves).

If you use offsetof, IMO you need a set of functions similar to this. They aren't exactly nice, but they're a lot nicer than doing all the punning everywhere you need to apply an offset to a pointer.

As ruslik hints, there is an extension in GCC which (if you don't mind non-portable code) treats the size of a void as 1, so you can use + on a void* to add an offset in bytes.

  • 1
    btw, the union-based punning is actually a GCC extension. With respect to the C++ standard it suffers from the same aliasing issues. And who says that ptrdiff_t has in any way a layout that's "compatible" to a void pointer? I wouldn't even use memcpy to do that (which would otherwise be the way to do it). – sellibitze Dec 22 '10 at 09:29
  • @sellibitze - I got the advice on using union-based puns here - http://stackoverflow.com/questions/3674814/how-to-resolve-pointer-alias-issues - if it's wrong, please say so there. –  Dec 22 '10 at 18:59