3

In Visual Studio C++ version 9 (and probably other versions too), the following code:

int a = sizeof(void);
void const *b = static_cast<void const *>("hello world");
b += 6;

Generates these errors:

error C2070: 'void': illegal sizeof operand
error C2036: 'const void *' : unknown size

This code works under GCC, which treats sizeof(void) as 1.

Is there some way around this limitation, as casting explicitly to char * for purposes of pointer arithmetic adds to the confusion (void * is well recognised and used as a typeless pointer to raw memory).

Update0

  • Please note, I'm well aware of the existence of the standard.
  • I want to do raw pointer arithmetic.
  • I take sizeof(void) to show that I'm well aware the fact that it isn't 1 is the cause of the problem.
  • The code example is simply to demonstrate what is required to generate the errors.
  • I know this isn't a "normal" way to use void, but this is C, and these things happen.
  • Yes, people need to do this at low-level. I'm not after why, I'm after how. If you want to know why, take a look at some kernel source, or your friendly glibc.

Update1

It seems this question has generated a great deal of confusion. The question is not about why having sizeof(void) == 1 is not standard, but what to do when it isn't.

In the instance that single-byte pointer arithmetic is to be done, it turns out that casting to char * is the correct answer, not because *(void *) has no size, but because the standard actually guarantees that *(char *) is always 1. Therefore the use of char * is always correct, and congruent with void * with the GCC extension for the purposes of raw pointer arithmetic.

To further reinforce the point, void * is the correct choice for pointers to typeless memory, and char * is the correct type to cast to for raw pointer arithmetic.

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • 10
    It's not a limitation. You shouldn't be doing anything with a `void *` pointer other than casting it to another pointer type. – Chris Lutz Dec 08 '09 at 03:22
  • 1
    What is void? It is nothing, and has no size. GCC has that with something to do with C, IIRC. – GManNickG Dec 08 '09 at 03:23
  • Why would you ever need to write code that needs to know the size of void??? – Justin Ethier Dec 08 '09 at 03:23
  • `void *` maybe very used as a pointer to typeless data, but `void` is never used as a datatype. What is `a`'s role in the code? You end up only using `b` in the other lines of code. – Jim Buck Dec 08 '09 at 03:24
  • 6
    Strictly, the MSVC compiler is right and GCC is wrong - sizeof(void) is a nonsense expression that should be a compilation error. According to the C standard, it is (_emphatically_) not 1. – Jonathan Leffler Dec 08 '09 at 03:41
  • Please read the question and the links carefully before commenting, some of these comments aren't very well thought out. – Matt Joiner Dec 08 '09 at 04:00
  • 5
    Don't come to us asking a question, then state your understanding of the situation is greater than ours. Doing any arithmetic with a raw void is meaningless, and any practice with it is bad practice. – GManNickG Dec 08 '09 at 04:12
  • 2
    Kernel source/glibc is practically written in assembler. You can do whatever you want to at that level because you know what you're doing. In C, it's assumed you _want_ a little bit of type-safety. If you want to use a `void *` pointer, you cast it to something else first. End of story. – Chris Lutz Dec 08 '09 at 04:15
  • 4
    "Yes, people need to do this at low-level". No, they don't *need* to do it. GCC provides it as a convenience, to save the programmer some typing. You could `#define advance(ARG1, ARG2) ((ARG1) = (void*)((ARG2) + (char*)(ARG1)))`, then `advance(b,6);`. You'd probably want a `plus` macro as well, to replace `b + 6`. – Steve Jessop Dec 08 '09 at 11:40
  • 1
    @Chris Lutz: "Kernel source/glibc is practically written in assembler". No, kernel source is almost overwhelmingly C. That's how kernels manage to be portable between architectures. The bare minimum is written in assembler. – DrPizza Dec 09 '09 at 08:39
  • 2
    I don't think many people "need" to do something which is, by definition, impossible. – Daniel Daranas Dec 09 '09 at 08:40
  • 3
    There is no good reason not to use a pointer to (unsigned) char for this purpose. It's what the NT kernel devs do, for example (no stupid gcc extensions for the NT kernel, after all). If you think it's ugly, create a macro or something. – DrPizza Dec 09 '09 at 08:41
  • 1
    As I've pointed out in my answer below, an appropriate answer now I have more information is that `char *` _is_ the correct pointer type to use for this. Not just because we all want to lark about how void is typeless blah blah. – Matt Joiner Dec 09 '09 at 12:42

8 Answers8

18

Incrementing a pointer is technically supposed to increment it by whatever size of thing that its pointing at. Void points at nothing, so the size is unknown.

Its a nicety for some compilers to let you increment void pointers.

Casting is annoying, because you have to either cast it to another pointer, and then back, or do something awkward like (*(char *)&voidptr) += 6

Personally, I'd just declare it as a char * for purposes of arithmetic

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Matthias Wandel
  • 6,383
  • 10
  • 33
  • 31
  • 1
    Maybe you wanted `(*(char **)&voidptr) += 6`? I don't believe the code snippet currently there does quite what you imply it does. – Managu Dec 08 '09 at 03:59
  • Managu is right. Yet, this would be an act or raw *reinterpretation* of `void *` pointer as a `char *` pointer. Reinterpretation is always a bad idea. Better use a *conversion* as in `voidptr = (char *) voidptr + 6`. – AnT stands with Russia Dec 08 '09 at 04:56
  • I've been implementing a linked list using void pointers. When the list is created it is passed a `size_t data_size` so it can perform copying operations etc. Now I've come to the problem of creating a list-to-array conversion routine. The intuitive (for me) thing to do was to add `data_size` to the void pointer to move it to the next item in the array... Never mind. I've upvoted this question because it has proven useful. – James Morris Mar 12 '10 at 01:30
10

In C language sizeof cannot be applied to incomplete types. void is an incomplete type, which is why you can't use it as operand of sizeof.

Pointer arithmetic of void * pointers is also not supported in C. In order to be used with pointer arithmetic the pointer has to point to object type, which void is not.

GCC allows both as a weird language extension.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 1
    Strangely enough it is not considered an error in _paranoid mode_ unless either `-Werror` or `-pedantic-errors` is specified. I just came across exactly the same conclusion when I took a look at the Standard. – D.Shawley Dec 08 '09 at 03:40
6

void * is meant to imply "pointer to unknown"

Adding 6 to a void pointer is therefore undefined, because you're asking the compiler to advance the pointer by "the size of 6 unknown objects".

You should not be doing it.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
3

There are two different questions here. The first is for void, and the second for void*. They are different types, and have little in common beside the name.

void is used mainly for function declarations/definitions (as the return type or to mean "takes no arguments"). You can't ever possibly have an object of type void. Ever. So it's hard to see a need to find out the size of that nonexistent object. GCC's behavior is nonstandard, and an intentional extension. However, I believe they chose sizeof(void) == 1 because the C++ standard requires every object to take at least one byte of space.

void* means "pointer to real data, but without the relevant type information." It is entirely possible to have void*; and you will run into them, a lot. However, because the type information is ignored you can't manipulate the pointer much. This is by design, because if you don't know what you have you really don't know what you can do with it.

But if you want to treat the memory as a collection of bytes then char* does that. A char is one byte, everywhere. A string of bytes is a char*. If you find this weird, use byte* (where you define byte as something like unsigned char).

Max Lybbert
  • 19,717
  • 4
  • 46
  • 69
  • 3
    No, GCC giving an answer of 1 is an implementation detail. `void` is an incomplete type, and as such it should not be possible to take the size of it. GCC is in error, here. – GManNickG Dec 08 '09 at 09:16
  • 3
    Maybe I should have been clearer. GCC's behavior is an intentional extension ( http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Pointer-Arith.html ), and I believe they picked a size of 1 because the C++ standard requires any object to take up at least one byte. – Max Lybbert Dec 09 '09 at 08:33
2

I can see the error on the first line at least - you have sizeof(void) and it should be sizeof(void*), no?

Chris Tonkinson
  • 13,823
  • 14
  • 58
  • 90
1

For purely pointing at raw data and incrementing that pointer by the number of bytes a chunk of data occupies, I always use char *. I then recast the pointer to a relevant data structure pointer once I need to treat it as something specific. Incrementing a void * isn't portable among compilers.

Jim Buck
  • 20,482
  • 11
  • 57
  • 74
  • Incrementing a `void *` is of course a terrible idea... but so is acting like your solution is better. Like most other `reinterpret_cast`s, casting from `char *` to an incompatible type of pointer and dereferencing the result isn't defined, violates aliasing rules, and subverts platform alignment requirements. So, unless all of your data structures are compatible through having only a single `char` member each, which is unlikely... the only "portable" thing about this advice is its role as a pure UB generator. – underscore_d Jul 29 '16 at 22:20
  • 1
    I posted this >6.5 years ago and assumed that one would use it if only they knew what they were doing for their platform. :) Having said that, on platforms that often require low-level programming to eke out full performance (think console games, where I spent the majority of my past 20 years), this is still common despite middleware like Unity making a decent penetration. (And, for the record, this method is often used *exactly* for the reason of having to deal with platform alignment requirements.) But, no worries, I only got one upvote so far in almost 7 years, so you're safe. ;) – Jim Buck Jul 30 '16 at 03:41
1

void * is well recognised and used as a typeless pointer to raw memory.

Correct. Not having a type means not having a size either.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
-3

It would appear the correct answer is to use char * for pointer arithmetic, because sizeof(char) is always defined to be 1, and to be of the finest addressable granularity on any platform.

So in short, there is no way around the limitation, char * is in fact the proper way to do it.

Matthias Wandel had the right answer but with a different justification.

Community
  • 1
  • 1
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • 1
    Your question was not about what would be the correct type for pointer arithmetic. Your question was about why MSVC spat an error for `sizeof( void )` and if there is "any way around this limitation" (which there is not, as Matthias and others pointed out correctly). Including some strong words towards people trying to be helpful. Be a man and accept another's answer instead of complaining how the correct answer didn't fit your broken question... – DevSolar Dec 09 '09 at 16:10
  • 1
    ...and a week later, there's your "accepted" answer rated -2, while the answer you claim has not the correct "justification" is rated 11... – DevSolar Dec 14 '09 at 09:25
  • i'm not changing it. i know what i meant, and i knew the answer when i saw it. "is there a way around this limitation?": "no, and here's why". if someone makes a more accurate answer, i'll be happy to change. Matthias' answer is quite correct, but not what i was after. – Matt Joiner Dec 14 '09 at 15:21