3

I really want to use some void casts to hold binary data but this is either g++ warning cascade or a lot of casting. Is there an easy and safe way to do void pointer arithmetics in C++ (preferably c++11 or higher)?

I am working only on posix systems with gnu compiler so that not a problem here.

Usecase:

  • I have void * ptr to data with size > 1GB.

  • I have other function to do things, lets call it stuff() its part of external library and gets (void *, size_t) as params.

  • stuff(ptr, n) is likely to mutate underlying memory. basically I need to pass slice of ptr*.

Code suppose to, is, and i guess, will not be portable.

I guess i will go just with -Wno-pointer-arithmetics if i wont be able to find some more elegant solution, but the one proposed in answers helped

  • 4
    you cannot do pointer arithmetics on void pointer. safe or not, it's impossible. – David Haim Apr 20 '16 at 14:49
  • 1
    Nope. Arithmetic doesn't work on `void` pointers. The solutions that you could try depend on your code, which you haven't shown. – Quentin Apr 20 '16 at 14:49
  • Why even use C-style pointers ? Just stuff your binary data into a suitable container, e.g. `std::vector`. – Paul R Apr 20 '16 at 14:51
  • 5
    Possible duplicate of [Void Pointer Arithmetic](http://stackoverflow.com/questions/3377977/void-pointer-arithmetic), [Performing arithmetic on a void pointer in C++](http://stackoverflow.com/questions/19801734/performing-arithmetic-on-a-void-pointer-in-c), or [Pointer arithmetic when void has unknown size](http://stackoverflow.com/questions/1864352/pointer-arithmetic-when-void-has-unknown-size). – callyalater Apr 20 '16 at 14:55
  • @callyalater topics are related but i dont think its dupliate – esavier Apr 20 '16 at 15:10
  • 3
    Why store "binary data" as `void` rather than bytes (i.e. `uint8_t`)? – GrahamS Apr 20 '16 at 15:12
  • There are ways to do something that looks like arithmetic on `void*`, but you need to specify how it's supposed to work. – Keith Thompson Apr 20 '16 at 15:52
  • @GrahamS: `unsigned char` is a more general byte type. In an implementation with `CHAR_BIT > 8`, the type `uint8_t` won't exist. – Keith Thompson Apr 20 '16 at 15:53
  • 2
    @KeithThompson: can't say I've ever encountered a system like that. Personally I'd rather use `uint8_t` as it it makes it clear that it is not character data and explicitly states we are expecting 8-bit bytes. – GrahamS Apr 20 '16 at 16:19
  • @GrahamS: Using `uint8_t` makes sense if you *want* your code to fail to compile on an exotic system with `CHAR_BIT > 8`. It's a way of asserting a compile time that bytes are 8 bits. But if you want your code to be portable to exotic systems, use `unsigned char` (typedef it as `byte` if you like) and don't assume that bytes are 8 bits. (Systems with `CHAR_BIT > 8` are usually DSPs.) – Keith Thompson Apr 20 '16 at 17:47
  • @KeithThompson: yeah that makes sense. Thanks. I'm usually coding for micros where if byte wasn't 8-bits the code wouldn't work anyway so compile-time failure makes sense for me. Out of interest, does the C++11 standard guarantee that an `unsigned char` is the same size as a byte? (Had a quick browse, but couldn't find it). – GrahamS Apr 20 '16 at 19:35
  • @GrahamS: Yes, it does. See the discussion of the `sizeof` operator. (A byte may be 8 or more bits.) – Keith Thompson Apr 20 '16 at 19:48

1 Answers1

-3

Depends on what you have in mind when asking about arithemtics. Following code is perfectly fine, and compilable by GNU g++ -std=c++11 :

#include <cstdlib>
#include <cstdio>

int main()
{
    void * x = std::malloc(100);
    std::printf("%p\n", x);
    std::printf("%p\n", x+20);
    return 0;
 }

(Edit2) Question is pretty confusing, but if gnu compiler is something to work on, void pointer arithmetics is perfectly ok. GNU basically defines void * as pointer with one byte increments, and by that all statements in above code are correct. I did not tested it with other compilers, and as far as this question is considered, I do not have to.

For compilers other than GNU, using unsigned integer type perfectly safe and correct : first cast pointer to either one of 1byte integer type:

  • size_t
  • uintptr_t / intptr_t
  • or if you know memory size and model - precise fixed width integer }

If ever memory addressing will be changed to any other weird size per cell - you would need to use type that after adding +1 to address will point to next physical storage cell.

Also to clarify = bool is not 1bit type... its padded (aliased) char with some wrapper magic inside.

esavier
  • 423
  • 4
  • 13
  • 9
    Pointer arithmetic works with the element type. How do you get the 20th `void`? The operation just doesn't make sense. If it does anything at all I believe it's a compiler enhancement and not part of the standard. – Mark Ransom Apr 20 '16 at 15:12
  • 1
    void is pointer na 8byte no-type. its same as take 20th byte of this region, do you want more? `uint64_t x =1; uint8_t biggest=((void*)(x))+7;` You are trying to objectify stuff, go lower, its not java. – esavier Apr 20 '16 at 15:15
  • 2
    (sorry, I couldn't resist) – zoska Apr 20 '16 at 15:21
  • 2
    Mark is right, arithmetic on `void` pointers is [a GCC extension](https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html), but nothing standard. – Quentin Apr 20 '16 at 15:21
  • `x+20` is meaningless when `x` is a `void` pointer because the size of `void` is not defined. If you want +20 to mean 20 bytes then `x` should be byte pointer (e.g. `uint8_t*`) – GrahamS Apr 20 '16 at 15:23
  • 2
    `void` has no size, adding value to pointer (e.g. `pointer + n`) get's you value of nth element. nth element is reached by moving to address - `pointer address + n * (size of element)`. No size of `void`, no arithmetic on `void` pointers. – zoska Apr 20 '16 at 15:23
  • [This question](http://stackoverflow.com/questions/13113301/how-void-pointer-arithmetic-is-happening-in-gcc) talks about the GCC extension as well. – callyalater Apr 20 '16 at 15:26
  • Yes, that code compiles with `g++ -std=c++11` (which is *not* a conforming C++ compiler), but you failed to mention the warning: "warning: pointer of type 'void *' used in arithmetic [-Wpointer-arith]". Also, converting a pointer to `int` and performing arithmetic is not reliable. `int` might not be big enough to hold a pointer value, and the mapping might not be straightforward (I've worked on systems where it isn't). You can convert a `void*` to `char*`, perform arithmetic, and then convert back to `void*` -- but then you probably should have used `char*` in the first place. – Keith Thompson Apr 20 '16 at 15:49
  • 2
    "*before c++11 void was incomplete type thereby void could not be called sizeof() on*" -- I don't believe C++11 changed anything in that area. If you claim that the C++11 standard made `sizeof (void)` valid, please cite the section of the standard that made that change. – Keith Thompson Apr 20 '16 at 15:50
  • C++11 still defines void as an incomplete type. See section "3.9.1 Fundamental types" which says "The void type has an empty set of values. The void type is an incomplete type that cannot be completed" http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf – GrahamS Apr 20 '16 at 15:59
  • 1
    What i see is fight over standard and syntax, not constructive comments. From answer I was able to obtain enough information's to pull out an working example and it fits my needs. –  Apr 21 '16 at 07:37
  • 1
    That's great. Be aware though that it's bad practice, non-standard, non-portable and may break unexpectedly with a future compiler upgrade. That's why we care about standards in the first place, after all. – Useless Apr 21 '16 at 16:41